* [PATCH v2 2/2] app/crypto-perf: support ML DSA
From: Pratik Senapati @ 2026-06-09 5:53 UTC (permalink / raw)
To: dev; +Cc: gakhil, kai.ji
In-Reply-To: <20260609055315.1539233-1-psenapati@marvell.com>
Add ML-DSA44 support to test-crypto-perf.
Signed-off-by: Pratik Senapati <psenapati@marvell.com>
---
app/test-crypto-perf/cperf_ops.c | 70 +
app/test-crypto-perf/cperf_options.h | 2 +
app/test-crypto-perf/cperf_options_parsing.c | 20 +-
app/test-crypto-perf/cperf_test_common.c | 3 +-
app/test-crypto-perf/cperf_test_vectors.c | 1661 ++++++++++++++++++
app/test-crypto-perf/cperf_test_vectors.h | 37 +
app/test-crypto-perf/main.c | 17 +
doc/guides/tools/cryptoperf.rst | 1 +
8 files changed, 1809 insertions(+), 2 deletions(-)
diff --git a/app/test-crypto-perf/cperf_ops.c b/app/test-crypto-perf/cperf_ops.c
index 806265f7bf..7d3a74b505 100644
--- a/app/test-crypto-perf/cperf_ops.c
+++ b/app/test-crypto-perf/cperf_ops.c
@@ -251,6 +251,58 @@ cperf_set_ops_asym_mlkem(struct rte_crypto_op **ops,
}
}
+static void
+cperf_set_ops_asym_mldsa(struct rte_crypto_op **ops,
+ uint32_t src_buf_offset __rte_unused,
+ uint32_t dst_buf_offset __rte_unused, uint16_t nb_ops,
+ void *sess,
+ const struct cperf_options *options,
+ const struct cperf_test_vector *test_vector __rte_unused,
+ uint16_t iv_offset __rte_unused,
+ uint32_t *imix_idx __rte_unused,
+ uint64_t *tsc_start __rte_unused)
+{
+ uint16_t i;
+
+ for (i = 0; i < nb_ops; i++) {
+ struct rte_crypto_asym_op *asym_op = ops[i]->asym;
+
+ ops[i]->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+ rte_crypto_op_attach_asym_session(ops[i], sess);
+
+ if (options->asym_op_type == RTE_CRYPTO_ASYM_OP_SIGN) {
+ asym_op->mldsa.op = RTE_CRYPTO_ML_DSA_OP_SIGN;
+ asym_op->mldsa.siggen.privkey.data = options->mldsa_data->privkey.data;
+ asym_op->mldsa.siggen.privkey.length = options->mldsa_data->privkey.length;
+ asym_op->mldsa.siggen.message.data = options->mldsa_data->message.data;
+ asym_op->mldsa.siggen.message.length = options->mldsa_data->message.length;
+ asym_op->mldsa.siggen.sign.data = options->mldsa_data->sign.data;
+ asym_op->mldsa.siggen.sign.length = options->mldsa_data->sign.length;
+ asym_op->mldsa.siggen.ctx.data = options->mldsa_data->ctx.data;
+ asym_op->mldsa.siggen.ctx.length = options->mldsa_data->ctx.length;
+ asym_op->mldsa.siggen.seed.data = options->mldsa_data->seed.data;
+ asym_op->mldsa.siggen.seed.length = options->mldsa_data->seed.length;
+ asym_op->mldsa.siggen.mu.data = options->mldsa_data->mu.data;
+ asym_op->mldsa.siggen.mu.length = options->mldsa_data->mu.length;
+ asym_op->mldsa.siggen.hash = options->mldsa_data->hash;
+ } else if (options->asym_op_type == RTE_CRYPTO_ASYM_OP_VERIFY) {
+ asym_op->mldsa.op = RTE_CRYPTO_ML_DSA_OP_VERIFY;
+ asym_op->mldsa.sigver.pubkey.data = options->mldsa_data->pubkey.data;
+ asym_op->mldsa.sigver.pubkey.length = options->mldsa_data->pubkey.length;
+ asym_op->mldsa.sigver.message.data = options->mldsa_data->message.data;
+ asym_op->mldsa.sigver.message.length = options->mldsa_data->message.length;
+ asym_op->mldsa.sigver.sign.data = options->mldsa_data->sign.data;
+ asym_op->mldsa.sigver.sign.length = options->mldsa_data->sign.length;
+ asym_op->mldsa.sigver.ctx.data = options->mldsa_data->ctx.data;
+ asym_op->mldsa.sigver.ctx.length = options->mldsa_data->ctx.length;
+ asym_op->mldsa.sigver.mu.data = options->mldsa_data->mu.data;
+ asym_op->mldsa.sigver.mu.length = options->mldsa_data->mu.length;
+ asym_op->mldsa.sigver.hash = options->mldsa_data->hash;
+ } else {
+ rte_panic("Unsupported ML-DSA operation type %d\n", options->asym_op_type);
+ }
+ }
+}
#ifdef RTE_LIB_SECURITY
static void
@@ -1269,6 +1321,21 @@ cperf_create_session(struct rte_mempool *sess_mp,
return asym_sess;
}
+ if (options->op_type == CPERF_ASYM_MLDSA44) {
+ xform.next = NULL;
+ xform.xform_type = RTE_CRYPTO_ASYM_XFORM_ML_DSA;
+ xform.mldsa.type = RTE_CRYPTO_ML_DSA_44;
+ xform.mldsa.sign_deterministic =
+ options->mldsa_data->sign_deterministic;
+ xform.mldsa.sign_prehash = false;
+
+ ret = rte_cryptodev_asym_session_create(dev_id, &xform, sess_mp, &asym_sess);
+ if (ret < 0) {
+ RTE_LOG(ERR, USER1, "ML-DSA Asym session create failed\n");
+ return NULL;
+ }
+ return asym_sess;
+ }
if (options->op_type == CPERF_ASYM_MLKEM512) {
xform.next = NULL;
@@ -1600,6 +1667,9 @@ cperf_get_op_functions(const struct cperf_options *options,
case CPERF_ASYM_SM2:
op_fns->populate_ops = cperf_set_ops_asym_sm2;
break;
+ case CPERF_ASYM_MLDSA44:
+ op_fns->populate_ops = cperf_set_ops_asym_mldsa;
+ break;
case CPERF_ASYM_MLKEM512:
op_fns->populate_ops = cperf_set_ops_asym_mlkem;
break;
diff --git a/app/test-crypto-perf/cperf_options.h b/app/test-crypto-perf/cperf_options.h
index 98b8eeec3e..d8ceca2424 100644
--- a/app/test-crypto-perf/cperf_options.h
+++ b/app/test-crypto-perf/cperf_options.h
@@ -101,6 +101,7 @@ enum cperf_op_type {
CPERF_ASYM_SECP521R1,
CPERF_ASYM_ED25519,
CPERF_ASYM_SM2,
+ CPERF_ASYM_MLDSA44,
CPERF_ASYM_MLKEM512,
CPERF_TLS,
};
@@ -189,6 +190,7 @@ struct cperf_options {
struct cperf_eddsa_test_data *eddsa_data;
struct cperf_sm2_test_data *sm2_data;
struct cperf_mlkem_test_data *mlkem_data;
+ struct cperf_mldsa_test_data *mldsa_data;
enum rte_crypto_asym_op_type asym_op_type;
enum rte_crypto_auth_algorithm asym_hash_alg;
struct cperf_rsa_test_data *rsa_data;
diff --git a/app/test-crypto-perf/cperf_options_parsing.c b/app/test-crypto-perf/cperf_options_parsing.c
index 34afa938c8..44c2a7173a 100644
--- a/app/test-crypto-perf/cperf_options_parsing.c
+++ b/app/test-crypto-perf/cperf_options_parsing.c
@@ -41,7 +41,7 @@ usage(char *progname)
" --optype cipher-only / auth-only / cipher-then-auth / auth-then-cipher /\n"
" aead / pdcp / docsis / ipsec / modex / rsa / secp192r1 /\n"
" secp224r1 / secp256r1 / secp384r1 / secp521r1 / eddsa / sm2 /\n"
- " mlkem_512 /\n"
+ " mlkem_512 / mldsa_44 /\n"
" tls-record : set operation type\n"
" --sessionless: enable session-less crypto operations\n"
" --shared-session: share 1 session across all queue pairs on crypto device\n"
@@ -560,6 +560,10 @@ parse_op_type(struct cperf_options *opts, const char *arg)
cperf_op_type_strs[CPERF_ASYM_SM2],
CPERF_ASYM_SM2
},
+ {
+ cperf_op_type_strs[CPERF_ASYM_MLDSA44],
+ CPERF_ASYM_MLDSA44
+ },
{
cperf_op_type_strs[CPERF_ASYM_MLKEM512],
CPERF_ASYM_MLKEM512
@@ -1180,6 +1184,7 @@ cperf_options_default(struct cperf_options *opts)
opts->eddsa_data = &ed25519_perf_data;
opts->sm2_data = &sm2_perf_data;
opts->mlkem_data = &mlkem_encap_perf_data[0];
+ opts->mldsa_data = &mldsa_sign_perf_data[0];
opts->asym_op_type = RTE_CRYPTO_ASYM_OP_ENCRYPT;
}
@@ -1709,6 +1714,17 @@ cperf_options_check(struct cperf_options *options)
}
#endif
+ if (options->op_type == CPERF_ASYM_MLDSA44) {
+ if (options->asym_op_type == RTE_CRYPTO_ASYM_OP_SIGN)
+ options->mldsa_data = &mldsa_sign_perf_data[0];
+ else if (options->asym_op_type == RTE_CRYPTO_ASYM_OP_VERIFY)
+ options->mldsa_data = &mldsa_verify_perf_data[0];
+ else {
+ RTE_LOG(ERR, USER1, "ML-DSA only supports sign and verify operations\n");
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -1759,6 +1775,8 @@ cperf_options_dump(struct cperf_options *opts)
rte_crypto_asym_op_strings[opts->asym_op_type]);
if (opts->op_type == CPERF_ASYM_RSA)
printf("# rsa test name: %s\n", opts->rsa_data->name);
+ if (opts->op_type == CPERF_ASYM_MLDSA44)
+ printf("# mldsa test name: %s\n", opts->mldsa_data->name);
if (opts->op_type == CPERF_ASYM_MLKEM512)
printf("# mlkem test name: %s\n", opts->mlkem_data->name);
}
diff --git a/app/test-crypto-perf/cperf_test_common.c b/app/test-crypto-perf/cperf_test_common.c
index 383d4bd940..0bcaa6dfd8 100644
--- a/app/test-crypto-perf/cperf_test_common.c
+++ b/app/test-crypto-perf/cperf_test_common.c
@@ -314,7 +314,8 @@ cperf_is_asym_test(const struct cperf_options *options)
options->op_type == CPERF_ASYM_SECP521R1 ||
options->op_type == CPERF_ASYM_ED25519 ||
options->op_type == CPERF_ASYM_SM2 ||
- options->op_type == CPERF_ASYM_MLKEM512)
+ options->op_type == CPERF_ASYM_MLKEM512 ||
+ options->op_type == CPERF_ASYM_MLDSA44)
return true;
return false;
diff --git a/app/test-crypto-perf/cperf_test_vectors.c b/app/test-crypto-perf/cperf_test_vectors.c
index 6e2435b004..a3b050af11 100644
--- a/app/test-crypto-perf/cperf_test_vectors.c
+++ b/app/test-crypto-perf/cperf_test_vectors.c
@@ -3934,6 +3934,1624 @@ uint8_t mlkem_512_sk[] = {
0x5E, 0x7A, 0xB9, 0x3A, 0x40, 0xAD, 0x38, 0x6A
};
+uint8_t mldsa_44_seed[] = {
+ 0xf4, 0x41, 0xc9, 0x62, 0x17, 0x32, 0x2c, 0xbc,
+ 0xcf, 0x05, 0xf7, 0x5b, 0xd5, 0xfb, 0x0a, 0x0a,
+ 0x78, 0xbf, 0xad, 0xab, 0x89, 0x6e, 0x88, 0xdb,
+ 0xb4, 0x08, 0x90, 0xe0, 0x16, 0x9b, 0xb6, 0x66,
+};
+
+uint8_t mldsa_44_privkey[] = {
+ 0xcc, 0x2c, 0x93, 0xce, 0xfc, 0x0b, 0xf6, 0x74,
+ 0x93, 0x28, 0x95, 0xe8, 0xc0, 0xc8, 0x83, 0xb8,
+ 0xc9, 0x0c, 0x9a, 0x5c, 0x18, 0xd2, 0x79, 0x5c,
+ 0xf3, 0x58, 0xd8, 0x02, 0x6c, 0x5e, 0xad, 0x79,
+ 0xc1, 0xae, 0x0a, 0x97, 0x90, 0x41, 0x10, 0x32,
+ 0x59, 0x46, 0x12, 0x27, 0x0a, 0xa3, 0xc7, 0xf0,
+ 0x74, 0x54, 0x3d, 0xb2, 0x24, 0xc2, 0xa2, 0xec,
+ 0xaf, 0x31, 0xa0, 0xf4, 0x78, 0x97, 0x7c, 0x6a,
+ 0xdc, 0x91, 0x87, 0x60, 0x01, 0xa9, 0x19, 0x2d,
+ 0x0d, 0xca, 0xb4, 0x14, 0x9d, 0x41, 0xe3, 0x18,
+ 0x4b, 0x99, 0x31, 0xfa, 0xf4, 0xfa, 0xc4, 0x75,
+ 0x93, 0x87, 0xc7, 0x7a, 0x8f, 0x0e, 0xc6, 0xb2,
+ 0xfa, 0xf6, 0x48, 0x84, 0x17, 0x42, 0x01, 0xcb,
+ 0xd2, 0x55, 0x40, 0x2f, 0x23, 0x21, 0x91, 0x11,
+ 0x40, 0x00, 0xdc, 0x91, 0x3d, 0xf5, 0x96, 0xdb,
+ 0xb3, 0x6d, 0xd5, 0xf4, 0xc5, 0x11, 0x96, 0x8f,
+ 0x13, 0x25, 0x4a, 0x24, 0xb3, 0x90, 0x9b, 0x16,
+ 0x30, 0x20, 0x96, 0x10, 0x10, 0x97, 0x6c, 0xd0,
+ 0x26, 0x26, 0x61, 0x84, 0x85, 0x1b, 0xb2, 0x81,
+ 0x5c, 0x10, 0x88, 0x48, 0xc8, 0x8d, 0x1c, 0x42,
+ 0x61, 0x19, 0x32, 0x04, 0x81, 0xa6, 0x89, 0x98,
+ 0x42, 0x62, 0x14, 0xa3, 0x90, 0xc8, 0xc2, 0x4c,
+ 0x41, 0x04, 0x2c, 0x5b, 0x26, 0x2a, 0xd1, 0x30,
+ 0x12, 0x18, 0x40, 0x71, 0x08, 0x98, 0x70, 0x60,
+ 0x40, 0x09, 0x4a, 0x44, 0x0a, 0x24, 0x43, 0x92,
+ 0x04, 0x20, 0x06, 0x80, 0xa2, 0x01, 0x18, 0x47,
+ 0x12, 0x23, 0xc7, 0x6c, 0x50, 0x32, 0x61, 0xda,
+ 0x26, 0x40, 0x84, 0x98, 0x90, 0xd3, 0x04, 0x66,
+ 0x52, 0xb8, 0x70, 0x99, 0x02, 0x6c, 0x64, 0xb2,
+ 0x00, 0x1b, 0x35, 0x90, 0x23, 0x00, 0x92, 0x01,
+ 0x02, 0x20, 0x12, 0x89, 0x25, 0x62, 0xa6, 0x4d,
+ 0x1b, 0x29, 0x08, 0x08, 0x46, 0x72, 0xa1, 0x18,
+ 0x11, 0x03, 0x80, 0x60, 0xd4, 0x38, 0x80, 0x64,
+ 0x36, 0x4e, 0x23, 0x30, 0x8e, 0x23, 0x81, 0x60,
+ 0xd1, 0x84, 0x89, 0xe2, 0xa8, 0x2d, 0x80, 0x92,
+ 0x61, 0x8a, 0x22, 0x28, 0x0a, 0xc9, 0x50, 0xe3,
+ 0x96, 0x40, 0x84, 0xa0, 0x0d, 0xd8, 0xc2, 0x2c,
+ 0xd1, 0x30, 0x10, 0x18, 0xa0, 0x48, 0xe2, 0xb2,
+ 0x04, 0x00, 0xa8, 0x29, 0x19, 0x42, 0x68, 0xa3,
+ 0xa2, 0x71, 0xd9, 0xc0, 0x45, 0xa2, 0xc6, 0x4c,
+ 0x51, 0x36, 0x71, 0xc1, 0x40, 0x02, 0x08, 0x12,
+ 0x72, 0x90, 0x04, 0x2e, 0x80, 0x30, 0x24, 0x8b,
+ 0x90, 0x44, 0x82, 0x82, 0x68, 0xa2, 0x84, 0x2d,
+ 0x08, 0x00, 0x61, 0x23, 0x82, 0x48, 0x00, 0x33,
+ 0x29, 0x58, 0x48, 0x86, 0x01, 0x01, 0x21, 0x62,
+ 0xa8, 0x91, 0xe3, 0x10, 0x6c, 0x58, 0x24, 0x09,
+ 0x0c, 0x14, 0x02, 0x63, 0x22, 0x20, 0x12, 0x48,
+ 0x70, 0x81, 0x26, 0x6e, 0x00, 0x86, 0x31, 0x1a,
+ 0x22, 0x65, 0x40, 0x38, 0x00, 0x02, 0x47, 0x09,
+ 0xc9, 0x82, 0x8c, 0x82, 0xa0, 0x2c, 0xd3, 0x04,
+ 0x45, 0x50, 0xb0, 0x28, 0xd0, 0x10, 0x8d, 0x1c,
+ 0x10, 0x52, 0x4b, 0x00, 0x66, 0xc8, 0xc0, 0x08,
+ 0x9a, 0xa8, 0x2d, 0xd4, 0x02, 0x8a, 0x1b, 0x35,
+ 0x65, 0x04, 0xc7, 0x28, 0x84, 0x38, 0x50, 0x18,
+ 0x20, 0x4a, 0x91, 0x18, 0x8c, 0x9b, 0x20, 0x09,
+ 0x94, 0x08, 0x71, 0x64, 0x06, 0x25, 0x20, 0x23,
+ 0x09, 0xd8, 0x82, 0x68, 0x5a, 0xa6, 0x31, 0x63,
+ 0x36, 0x32, 0x5c, 0x12, 0x62, 0xdb, 0x32, 0x6e,
+ 0x14, 0x93, 0x68, 0x9a, 0x34, 0x80, 0x83, 0x44,
+ 0x4a, 0x18, 0x13, 0x49, 0x43, 0xb8, 0x0d, 0xda,
+ 0x92, 0x41, 0x42, 0xb8, 0x84, 0x52, 0x94, 0x91,
+ 0x04, 0x05, 0x4d, 0xa2, 0x38, 0x64, 0x01, 0x19,
+ 0x05, 0x18, 0xa2, 0x4d, 0x90, 0x34, 0x26, 0x91,
+ 0x30, 0x68, 0x1c, 0x14, 0x44, 0x4b, 0x18, 0x22,
+ 0x12, 0x90, 0x91, 0x42, 0x96, 0x91, 0x19, 0x48,
+ 0x4c, 0x24, 0x46, 0x80, 0xc3, 0xb8, 0x8c, 0x1c,
+ 0x80, 0x8d, 0x18, 0x45, 0x88, 0xd8, 0x94, 0x4c,
+ 0x13, 0x02, 0x65, 0xd3, 0x22, 0x29, 0x49, 0x04,
+ 0x82, 0x04, 0xc2, 0x40, 0x04, 0x34, 0x21, 0xe1,
+ 0x34, 0x46, 0x20, 0x90, 0x44, 0x93, 0x14, 0x44,
+ 0xdb, 0xc0, 0x4d, 0x1b, 0xa2, 0x24, 0x5a, 0x24,
+ 0x68, 0x10, 0x46, 0x66, 0x11, 0x43, 0x29, 0xd0,
+ 0x90, 0x0d, 0x49, 0x12, 0x4c, 0xc1, 0x96, 0x2c,
+ 0xdb, 0x22, 0x65, 0xe4, 0x16, 0x24, 0xd1, 0x24,
+ 0x26, 0x53, 0xb8, 0x45, 0x8a, 0xb4, 0x11, 0x04,
+ 0x96, 0x28, 0x80, 0x22, 0x8e, 0xd1, 0x10, 0x05,
+ 0x44, 0x44, 0x8a, 0x5c, 0xb4, 0x50, 0xdc, 0x10,
+ 0x02, 0xc1, 0xa2, 0x4c, 0x11, 0x05, 0x2c, 0x21,
+ 0x39, 0x6a, 0x64, 0x36, 0x01, 0x09, 0xc3, 0x0c,
+ 0x9a, 0x24, 0x52, 0x92, 0x20, 0x0a, 0xd2, 0xa8,
+ 0x49, 0x99, 0xc6, 0x8d, 0x50, 0x26, 0x62, 0x09,
+ 0x42, 0x05, 0x5b, 0xc0, 0x41, 0xd0, 0x22, 0x25,
+ 0x09, 0xb4, 0x2d, 0x98, 0xa2, 0x24, 0x12, 0x84,
+ 0x0d, 0xca, 0x98, 0x11, 0x22, 0x80, 0x21, 0x1b,
+ 0x00, 0x44, 0x84, 0xc6, 0x89, 0x92, 0x48, 0x42,
+ 0x50, 0xc8, 0x60, 0x24, 0x15, 0x69, 0xa2, 0x48,
+ 0x06, 0xc4, 0xb0, 0x24, 0x63, 0x14, 0x40, 0x12,
+ 0xc4, 0x61, 0x82, 0x30, 0x60, 0x88, 0x96, 0x89,
+ 0xc9, 0xc0, 0x89, 0x12, 0x36, 0x82, 0x8c, 0xc0,
+ 0x09, 0xc0, 0x88, 0x91, 0xdb, 0x10, 0x64, 0x08,
+ 0x36, 0x71, 0x94, 0x10, 0x46, 0x20, 0x83, 0x10,
+ 0x13, 0x13, 0x4c, 0x08, 0x28, 0x45, 0x24, 0xb9,
+ 0x64, 0x09, 0xb0, 0x48, 0x1c, 0x25, 0x50, 0x23,
+ 0x40, 0x90, 0xe0, 0x96, 0x50, 0x9a, 0x38, 0x41,
+ 0xcc, 0xb2, 0x2c, 0xdb, 0x04, 0x66, 0x61, 0x48,
+ 0x30, 0x02, 0x34, 0x4e, 0xd1, 0xc2, 0x85, 0xc9,
+ 0x06, 0x41, 0x19, 0x30, 0x69, 0xc8, 0x94, 0x68,
+ 0x1c, 0x83, 0x70, 0x03, 0x10, 0x4d, 0xc2, 0x16,
+ 0x4e, 0x64, 0x92, 0x30, 0x60, 0x16, 0x84, 0xa2,
+ 0xa8, 0x90, 0xa4, 0x38, 0x11, 0x0a, 0x88, 0x05,
+ 0x10, 0x93, 0x88, 0x43, 0x06, 0x10, 0x18, 0x10,
+ 0x70, 0x03, 0x28, 0x42, 0x89, 0x28, 0x8d, 0x8a,
+ 0xa8, 0x09, 0x94, 0x42, 0x85, 0xa3, 0x10, 0x61,
+ 0x0c, 0x45, 0x50, 0x04, 0x31, 0x4c, 0xd1, 0x10,
+ 0x12, 0x8b, 0x96, 0x05, 0x03, 0xa0, 0x89, 0x21,
+ 0xc4, 0x4d, 0x61, 0xc8, 0x61, 0x09, 0x99, 0x10,
+ 0x59, 0x96, 0x49, 0x00, 0x89, 0x08, 0x23, 0x00,
+ 0x10, 0xcc, 0xa4, 0x61, 0x01, 0x25, 0x80, 0x21,
+ 0x31, 0x09, 0x13, 0x28, 0x0d, 0x1c, 0x05, 0x85,
+ 0x62, 0x92, 0x44, 0x09, 0x10, 0x8a, 0x5a, 0xa6,
+ 0x20, 0x89, 0xb0, 0x20, 0x0c, 0xb3, 0x01, 0xc9,
+ 0x26, 0x61, 0x0b, 0x34, 0x6a, 0x8b, 0x44, 0x0e,
+ 0xf2, 0x47, 0x18, 0xf8, 0x4a, 0xfa, 0x45, 0x60,
+ 0x87, 0xeb, 0x0f, 0xff, 0x75, 0xa6, 0xba, 0x18,
+ 0x9a, 0x7d, 0x37, 0xc4, 0xc7, 0x7e, 0x1a, 0xc9,
+ 0x0d, 0x06, 0x53, 0xca, 0xf0, 0x2c, 0xe9, 0xe9,
+ 0x4b, 0x5f, 0x8b, 0xbc, 0x77, 0xc6, 0x71, 0x68,
+ 0x4f, 0x8c, 0x3b, 0x30, 0x59, 0x91, 0xf0, 0xb5,
+ 0x6d, 0xa6, 0x28, 0x2c, 0xd4, 0x0a, 0x00, 0x27,
+ 0x6a, 0x39, 0x17, 0x88, 0xa9, 0x93, 0xbb, 0x6e,
+ 0xda, 0x3e, 0x4b, 0xb7, 0x1b, 0x6a, 0xb2, 0xe2,
+ 0xc4, 0x6f, 0x21, 0x78, 0x74, 0xff, 0xa2, 0x02,
+ 0x65, 0x68, 0xa4, 0xce, 0xb4, 0xfe, 0x0c, 0x18,
+ 0x59, 0xb9, 0xc8, 0x33, 0x41, 0x27, 0xa1, 0x4b,
+ 0xcf, 0xe9, 0xa9, 0xd7, 0x2d, 0xf9, 0xcd, 0xc6,
+ 0xde, 0x4e, 0x1d, 0x7d, 0x07, 0xf4, 0xda, 0xed,
+ 0x89, 0xa1, 0xef, 0xbc, 0xec, 0x1b, 0xc3, 0x07,
+ 0xfd, 0xf5, 0x96, 0xa3, 0x6c, 0x70, 0xc8, 0xb9,
+ 0x9f, 0x46, 0x0a, 0xad, 0x46, 0x01, 0xa1, 0x92,
+ 0x7c, 0xd1, 0x12, 0x78, 0x89, 0x89, 0x98, 0x68,
+ 0x9e, 0xdd, 0xd9, 0x7b, 0x9f, 0x2b, 0x29, 0xc1,
+ 0x0e, 0x29, 0xb0, 0x44, 0x7c, 0x22, 0xd7, 0x67,
+ 0x47, 0x91, 0xf0, 0xf8, 0x56, 0x79, 0x89, 0x42,
+ 0x95, 0x60, 0x53, 0x32, 0xc1, 0x14, 0x48, 0x56,
+ 0x67, 0x00, 0x80, 0x86, 0xcd, 0x80, 0x21, 0x75,
+ 0xe8, 0xe2, 0x41, 0x6a, 0x5d, 0xb2, 0x12, 0x57,
+ 0x1e, 0x83, 0x34, 0xa4, 0x95, 0x4e, 0x0e, 0x71,
+ 0xac, 0xcb, 0x09, 0xef, 0xea, 0x4e, 0xe0, 0x4d,
+ 0x44, 0xb2, 0x67, 0xd2, 0x6e, 0x78, 0x01, 0xb5,
+ 0x09, 0x64, 0xa7, 0xdf, 0xe6, 0x16, 0x72, 0x6b,
+ 0x19, 0xe5, 0x88, 0x8a, 0x06, 0xae, 0x0a, 0x93,
+ 0xdb, 0xee, 0x0e, 0xf6, 0x52, 0x84, 0x95, 0x2b,
+ 0xf8, 0xf4, 0xcd, 0x5d, 0x8b, 0x3a, 0x86, 0x87,
+ 0x8e, 0x8b, 0x97, 0x65, 0xb1, 0xd6, 0x50, 0xbc,
+ 0xa7, 0xf0, 0x32, 0xb5, 0x39, 0x1e, 0x10, 0x7d,
+ 0x96, 0x11, 0xc1, 0xe8, 0x47, 0xfa, 0xdd, 0x24,
+ 0x22, 0xb6, 0x43, 0xb2, 0x41, 0x95, 0x98, 0x1a,
+ 0x3f, 0x0f, 0x9a, 0xd3, 0xc4, 0x10, 0x19, 0x85,
+ 0x0a, 0x0d, 0xde, 0xb7, 0x76, 0xec, 0xe3, 0x57,
+ 0x2e, 0x38, 0x4e, 0xb1, 0x2e, 0x4a, 0xaf, 0xc8,
+ 0x78, 0xa7, 0xb3, 0x1e, 0xaf, 0xe0, 0xe4, 0xbb,
+ 0xc8, 0x0b, 0x24, 0x04, 0x08, 0xd2, 0xbc, 0x91,
+ 0xca, 0x8e, 0x4e, 0x85, 0x39, 0x76, 0x20, 0xc9,
+ 0xa7, 0x47, 0x8b, 0x6a, 0xd9, 0xc8, 0xb7, 0xb0,
+ 0xa5, 0xa2, 0x85, 0x48, 0x4c, 0xcb, 0x16, 0xaf,
+ 0x45, 0x48, 0x00, 0xbe, 0x67, 0xef, 0x67, 0x65,
+ 0xa3, 0x9d, 0x43, 0x07, 0x59, 0x88, 0x9a, 0xad,
+ 0xe5, 0xad, 0x1e, 0xeb, 0xd5, 0xd4, 0xc7, 0xa4,
+ 0xb9, 0x40, 0x70, 0x2c, 0xe1, 0xcb, 0x5c, 0x3f,
+ 0x49, 0x6b, 0x51, 0xbf, 0xd3, 0xb7, 0xea, 0x33,
+ 0x52, 0x73, 0xcf, 0x26, 0x19, 0x54, 0x1d, 0xb6,
+ 0x33, 0x5d, 0x1a, 0x88, 0xdb, 0xd6, 0xfe, 0xae,
+ 0xf4, 0x45, 0x67, 0x80, 0x8a, 0xfc, 0xc4, 0xbe,
+ 0xfb, 0x6a, 0x4a, 0x75, 0x88, 0x35, 0x26, 0x1f,
+ 0x90, 0x65, 0x26, 0x5e, 0xb8, 0x0d, 0x15, 0x9d,
+ 0x70, 0x76, 0xf2, 0xfd, 0xed, 0x55, 0x71, 0x2b,
+ 0xe8, 0x2d, 0xc0, 0x28, 0xee, 0x53, 0x7c, 0xa1,
+ 0x3e, 0x86, 0x74, 0xa2, 0xd3, 0x9e, 0x2c, 0x70,
+ 0x15, 0x3a, 0x90, 0xfd, 0x1d, 0xac, 0x81, 0x2d,
+ 0xa6, 0x6a, 0xe6, 0xd7, 0x7f, 0xd9, 0x97, 0xc9,
+ 0x47, 0x7c, 0x07, 0xe6, 0x35, 0x45, 0xc9, 0x1f,
+ 0x08, 0xbc, 0x14, 0xdb, 0x12, 0x84, 0xc3, 0xc8,
+ 0xe2, 0x86, 0xa3, 0xa2, 0x1e, 0xfb, 0x3f, 0xca,
+ 0x92, 0x04, 0xe0, 0x6b, 0x29, 0xe0, 0xe0, 0x23,
+ 0x51, 0x40, 0x8e, 0xec, 0xf8, 0x87, 0xa2, 0x7a,
+ 0x2d, 0x8b, 0xc2, 0x62, 0x8c, 0x29, 0x82, 0x4b,
+ 0x86, 0x1a, 0xa7, 0xc6, 0xaa, 0x24, 0x5f, 0x24,
+ 0x03, 0x20, 0xa8, 0x3c, 0xa3, 0xcb, 0xd1, 0x60,
+ 0x64, 0x7d, 0x22, 0x9b, 0x07, 0x46, 0x1e, 0xff,
+ 0x43, 0xa9, 0x38, 0x34, 0x0f, 0x01, 0x00, 0x7f,
+ 0xc6, 0xcb, 0x0a, 0xed, 0x73, 0xc0, 0xfb, 0x77,
+ 0x80, 0x8c, 0x2c, 0x4c, 0xa5, 0x20, 0xe8, 0xcf,
+ 0x37, 0xf9, 0x00, 0x12, 0xe1, 0x6c, 0xb5, 0x9a,
+ 0x91, 0xbe, 0x1f, 0xaf, 0xf1, 0x8c, 0x6e, 0x09,
+ 0xea, 0xcf, 0xac, 0x43, 0x6e, 0x32, 0xd0, 0xf4,
+ 0x89, 0x4e, 0x42, 0xc2, 0xe7, 0x84, 0x7a, 0x66,
+ 0xb5, 0x2b, 0x5c, 0x7d, 0x83, 0x4b, 0xd4, 0x3d,
+ 0x81, 0x6d, 0x68, 0xb9, 0x72, 0xe5, 0xd5, 0xe5,
+ 0xf5, 0x9c, 0x4d, 0x95, 0xcd, 0xcd, 0x4d, 0x9a,
+ 0x4e, 0x69, 0xb9, 0x8a, 0x1e, 0x96, 0x69, 0xc0,
+ 0xe0, 0x39, 0x02, 0x21, 0x1c, 0x82, 0xd9, 0x5b,
+ 0xe5, 0xde, 0x34, 0xff, 0xf0, 0x15, 0xc7, 0x9a,
+ 0x62, 0x83, 0xca, 0xa3, 0x70, 0x15, 0xeb, 0x8f,
+ 0x73, 0x0e, 0xa9, 0x9c, 0xe9, 0xe3, 0xe7, 0xfc,
+ 0xb4, 0xcb, 0xac, 0xdf, 0x61, 0x91, 0xf3, 0x4b,
+ 0x87, 0xa6, 0x29, 0xea, 0x36, 0x81, 0x07, 0x3e,
+ 0xae, 0x69, 0xee, 0x87, 0x2a, 0x30, 0x1c, 0x97,
+ 0x96, 0x40, 0x08, 0x48, 0xcf, 0x5f, 0xfe, 0x57,
+ 0x23, 0xfd, 0xb7, 0x9a, 0x69, 0xef, 0xf5, 0x6e,
+ 0xc9, 0xdd, 0x95, 0x2b, 0x17, 0xd5, 0x2c, 0xad,
+ 0xa4, 0x49, 0x78, 0xb1, 0xd1, 0x00, 0xe7, 0xca,
+ 0xcb, 0x20, 0x9e, 0xba, 0xea, 0xc8, 0xd4, 0x9b,
+ 0x84, 0xac, 0x0b, 0xf0, 0x3b, 0x2c, 0xf0, 0x95,
+ 0x3b, 0x5b, 0xf8, 0xfe, 0xe5, 0xc6, 0xee, 0x7c,
+ 0x9e, 0x41, 0xf0, 0xef, 0xcf, 0x4d, 0xdd, 0xe8,
+ 0x63, 0x6b, 0xcf, 0xe9, 0xd2, 0x80, 0x98, 0xf9,
+ 0x7d, 0x22, 0x7e, 0xfc, 0xdd, 0x50, 0x6b, 0xa3,
+ 0x6d, 0x7c, 0xed, 0x35, 0xbc, 0x28, 0x64, 0x03,
+ 0xe6, 0x01, 0xac, 0x7c, 0xe1, 0x9b, 0x08, 0x6f,
+ 0xd8, 0xdc, 0xaf, 0xb6, 0x9d, 0x4c, 0xdf, 0xb1,
+ 0xde, 0xf4, 0x90, 0x5b, 0x46, 0xee, 0x7d, 0x28,
+ 0xfb, 0xaa, 0xa9, 0x69, 0x47, 0xf5, 0x52, 0x74,
+ 0x97, 0x9f, 0x8b, 0xbb, 0x26, 0x8f, 0x0d, 0x89,
+ 0x2f, 0xc9, 0x57, 0xac, 0x2f, 0x88, 0x12, 0xdd,
+ 0x12, 0x2f, 0x75, 0x97, 0xc7, 0x7b, 0x45, 0x46,
+ 0x3a, 0x52, 0x4b, 0xf6, 0x76, 0xe0, 0x99, 0xef,
+ 0xbe, 0xbf, 0xed, 0x0d, 0x32, 0xed, 0xc6, 0x5e,
+ 0x6a, 0xe6, 0x0e, 0x12, 0xd4, 0xce, 0xf8, 0x0c,
+ 0x7b, 0x4f, 0x1d, 0x3b, 0xf8, 0xaf, 0xdd, 0xd1,
+ 0x78, 0x74, 0x59, 0xc7, 0xe4, 0xbc, 0xe3, 0xdd,
+ 0x4a, 0xa7, 0x77, 0xa5, 0xcd, 0x80, 0x7c, 0x6b,
+ 0x19, 0x46, 0x3d, 0xbd, 0x0a, 0x75, 0x48, 0xfa,
+ 0x1c, 0xee, 0x02, 0xe9, 0x79, 0x10, 0x6c, 0xb4,
+ 0xb3, 0xb2, 0xbe, 0xc8, 0x5c, 0xd1, 0xa1, 0xe2,
+ 0xd5, 0x0a, 0xb5, 0xf3, 0x0c, 0x3f, 0x03, 0xb9,
+ 0x2f, 0x61, 0x44, 0x95, 0xe1, 0x16, 0xcb, 0xc1,
+ 0xee, 0xb3, 0xb8, 0x85, 0xd6, 0x1c, 0xf4, 0xfa,
+ 0x86, 0x73, 0xc5, 0xf3, 0xba, 0xb5, 0xe0, 0x95,
+ 0x34, 0x95, 0x72, 0xfa, 0xa7, 0xb8, 0x50, 0xba,
+ 0xfb, 0xa6, 0x3c, 0x0f, 0x3c, 0xe3, 0xaa, 0x56,
+ 0x05, 0xaf, 0x08, 0xec, 0x50, 0x12, 0x73, 0x25,
+ 0x29, 0x72, 0xf5, 0xf6, 0xee, 0x06, 0xe4, 0x05,
+ 0x1a, 0xe1, 0x1a, 0x13, 0x3f, 0xa3, 0x55, 0x16,
+ 0x12, 0x17, 0x88, 0xd2, 0xa7, 0xc1, 0xd0, 0xf2,
+ 0x7d, 0x51, 0x46, 0x36, 0x2e, 0x77, 0xa8, 0x02,
+ 0x67, 0xad, 0xe7, 0x63, 0xaa, 0xbf, 0xe5, 0xbf,
+ 0xa1, 0xab, 0xc4, 0xf6, 0x72, 0xae, 0xdf, 0x79,
+ 0x0e, 0x82, 0x47, 0xb5, 0xf4, 0x48, 0x39, 0x22,
+ 0xe3, 0x0a, 0x94, 0x5e, 0x3a, 0x4b, 0xa6, 0xa7,
+ 0x5c, 0xb8, 0xec, 0x3e, 0x10, 0xae, 0x94, 0x34,
+ 0x2c, 0xc0, 0x4b, 0xdd, 0xca, 0x4d, 0xc9, 0x7c,
+ 0xf8, 0x2e, 0x32, 0x4e, 0x00, 0x2c, 0x34, 0x71,
+ 0x28, 0xad, 0xd5, 0xcb, 0x19, 0xb8, 0x1d, 0xaa,
+ 0x85, 0xac, 0xec, 0x16, 0xb6, 0x1f, 0x95, 0xc5,
+ 0xa9, 0x4b, 0x8a, 0xfc, 0x70, 0xb7, 0x34, 0xb0,
+ 0x63, 0x55, 0xff, 0x15, 0xc2, 0x72, 0x74, 0xe0,
+ 0x6d, 0x01, 0x3d, 0xf0, 0x6a, 0xab, 0x4b, 0x8a,
+ 0x72, 0xdc, 0x2b, 0x0a, 0x8a, 0xf4, 0x02, 0x1b,
+ 0x0b, 0x51, 0xd8, 0xf7, 0x17, 0xcf, 0x48, 0xf0,
+ 0x97, 0xa0, 0xc2, 0x7a, 0xc4, 0x64, 0x59, 0x2a,
+ 0xa3, 0x27, 0xbe, 0x3b, 0xf7, 0xc5, 0x6d, 0x51,
+ 0x29, 0xe2, 0x68, 0x87, 0x75, 0x71, 0x72, 0xac,
+ 0xc8, 0xc1, 0xc8, 0xe5, 0xf6, 0x8a, 0x27, 0x8c,
+ 0x45, 0x03, 0x10, 0xf7, 0x1a, 0xff, 0x1b, 0x04,
+ 0x1c, 0xaf, 0x27, 0x7a, 0x57, 0xac, 0x0f, 0x57,
+ 0x2a, 0x74, 0xd0, 0x46, 0x64, 0xbf, 0xc9, 0xe8,
+ 0x35, 0x6b, 0x5c, 0x79, 0x9a, 0x51, 0xeb, 0xd1,
+ 0xb3, 0x1d, 0xfd, 0x2f, 0x83, 0x2e, 0x24, 0x95,
+ 0x94, 0xc7, 0x9d, 0x9f, 0x5d, 0x5c, 0x8e, 0x6c,
+ 0x8f, 0xfc, 0xce, 0x89, 0x67, 0x9b, 0x38, 0x4b,
+ 0x0d, 0x44, 0x9a, 0xb5, 0x74, 0xbf, 0x88, 0x90,
+ 0xa1, 0xf2, 0xc4, 0xd2, 0xb3, 0x07, 0xe5, 0x34,
+ 0x62, 0xc0, 0xfc, 0x3f, 0xdb, 0x77, 0x8e, 0x84,
+ 0x61, 0xc1, 0x15, 0xf6, 0x5f, 0x5d, 0x73, 0xbc,
+ 0x0c, 0x70, 0x32, 0xeb, 0x2c, 0xd3, 0x19, 0x83,
+ 0x22, 0xfa, 0x5b, 0xcc, 0x5f, 0xbf, 0xbe, 0xfc,
+ 0x3c, 0x28, 0x74, 0x2d, 0x33, 0x8f, 0x74, 0xe5,
+ 0xca, 0xc9, 0x84, 0x8f, 0xba, 0x48, 0x11, 0x84,
+ 0x33, 0xf0, 0x7d, 0x5c, 0xad, 0x47, 0x36, 0xf7,
+ 0x33, 0xb0, 0xbb, 0x44, 0x65, 0x72, 0x45, 0xd1,
+ 0x40, 0x4c, 0x39, 0x8b, 0x16, 0x90, 0x74, 0xa3,
+ 0xd2, 0x3c, 0xc6, 0x7a, 0xa4, 0x4f, 0x0d, 0x9a,
+ 0xe1, 0xfd, 0x49, 0x82, 0xc6, 0x69, 0xf7, 0xe7,
+ 0x3d, 0xeb, 0x2b, 0xbe, 0xfd, 0x1a, 0x73, 0x2c,
+ 0xf3, 0xbc, 0xd6, 0xaa, 0xaa, 0x54, 0x22, 0x5c,
+ 0x54, 0x92, 0x73, 0xe3, 0x79, 0x0a, 0x87, 0x20,
+ 0x82, 0xdb, 0x02, 0x42, 0x81, 0xb1, 0xf7, 0x0d,
+ 0xf0, 0xd8, 0x56, 0x0f, 0x74, 0x0c, 0x65, 0x7c,
+ 0x8c, 0x96, 0xb9, 0x9f, 0xfa, 0xb6, 0x48, 0x66,
+ 0xf1, 0xbe, 0xf8, 0x46, 0x70, 0xe5, 0x26, 0xc1,
+ 0x68, 0x7f, 0x81, 0x72, 0x14, 0x2f, 0x96, 0x22,
+ 0x05, 0xd1, 0xc0, 0xb8, 0x93, 0x9d, 0x02, 0x8b,
+ 0xff, 0x0b, 0x2d, 0xb9, 0x01, 0xaa, 0x61, 0x09,
+ 0x9d, 0x55, 0x21, 0xdd, 0xda, 0xec, 0x44, 0xce,
+ 0x00, 0x98, 0xf8, 0x34, 0x86, 0x49, 0xd4, 0x72,
+ 0x90, 0xfb, 0xd7, 0xb1, 0x33, 0xb9, 0xe5, 0xd3,
+ 0xc0, 0x27, 0x88, 0x4b, 0x6d, 0x84, 0x34, 0x7c,
+ 0x77, 0x7e, 0xcf, 0x27, 0x4d, 0x5f, 0x1d, 0xb4,
+ 0xb4, 0xac, 0xcc, 0x7d, 0x83, 0xc2, 0x89, 0x3d,
+ 0xeb, 0xb6, 0xa3, 0x57, 0x30, 0xbc, 0x94, 0x9f,
+ 0xe9, 0x63, 0xca, 0x7d, 0xa3, 0x9d, 0x0a, 0x43,
+ 0xed, 0x4a, 0xfd, 0xd3, 0x5e, 0x23, 0x97, 0x75,
+ 0x28, 0x97, 0xaa, 0x0c, 0xf9, 0xa1, 0x03, 0xb1,
+ 0x55, 0x82, 0xec, 0xcc, 0x91, 0x27, 0xf4, 0xcf,
+ 0x63, 0x10, 0xf3, 0xd3, 0x8b, 0x5c, 0xa8, 0xc2,
+ 0x58, 0x4d, 0xf5, 0x67, 0xe9, 0xe1, 0xc2, 0xf2,
+ 0x11, 0x5e, 0xf2, 0xe1, 0x1c, 0xf2, 0x0c, 0x50,
+ 0x71, 0x9f, 0xd1, 0x1c, 0xb8, 0x82, 0x7d, 0x3b,
+ 0x23, 0x90, 0x4e, 0x08, 0xbf, 0x51, 0xa1, 0xc9,
+ 0xe9, 0x90, 0x07, 0x4e, 0xb3, 0xcc, 0x72, 0xbf,
+ 0x2c, 0x87, 0x18, 0x3b, 0xc7, 0x29, 0x8a, 0x3b,
+ 0x0b, 0x4c, 0x55, 0x20, 0x08, 0xb0, 0xa3, 0x04,
+ 0xf9, 0x6b, 0x53, 0x84, 0x4c, 0xef, 0xc1, 0xc6,
+ 0xa4, 0xa9, 0xba, 0xe6, 0xb8, 0x72, 0x60, 0x6b,
+ 0x2d, 0x25, 0x08, 0xc1, 0xd4, 0x4e, 0x0b, 0xcb,
+ 0xe9, 0x71, 0x9b, 0x5a, 0x9a, 0x1e, 0x21, 0x9a,
+ 0x0a, 0xd0, 0x52, 0x82, 0xe9, 0x31, 0x45, 0x9e,
+ 0xe4, 0x85, 0x6b, 0xac, 0x8e, 0x7c, 0x73, 0x0c,
+ 0x0d, 0xd6, 0x54, 0x27, 0x5a, 0xce, 0xc8, 0x07,
+ 0x19, 0x84, 0x8b, 0xee, 0x0f, 0x6f, 0x8b, 0xbc,
+ 0x0c, 0x1b, 0xe0, 0x08, 0x64, 0xa6, 0xe6, 0xe1,
+ 0xf8, 0x56, 0x5e, 0xe8, 0x27, 0x7d, 0x26, 0xee,
+ 0x20, 0x5e, 0x3d, 0x2e, 0x84, 0xdc, 0x50, 0xb0,
+ 0x16, 0x3f, 0x8c, 0xec, 0xa9, 0xd3, 0x61, 0x85,
+ 0x5a, 0xba, 0x02, 0x82, 0x65, 0x30, 0xdb, 0x23,
+ 0x1c, 0xcb, 0xc3, 0xe6, 0x80, 0x5e, 0x4f, 0x6e,
+ 0xd8, 0x3b, 0x5e, 0xce, 0x67, 0xbb, 0xdb, 0x22,
+ 0xac, 0xf1, 0x32, 0x53, 0x6a, 0xd6, 0x43, 0x1a,
+ 0xf0, 0x11, 0xc5, 0x0f, 0xc5, 0x12, 0xdf, 0xe6,
+ 0x91, 0x8b, 0x15, 0xf4, 0x41, 0xd9, 0xe3, 0x51,
+};
+
+uint8_t mldsa_44_pubkey[] = {
+ 0xcc, 0x2c, 0x93, 0xce, 0xfc, 0x0b, 0xf6, 0x74,
+ 0x93, 0x28, 0x95, 0xe8, 0xc0, 0xc8, 0x83, 0xb8,
+ 0xc9, 0x0c, 0x9a, 0x5c, 0x18, 0xd2, 0x79, 0x5c,
+ 0xf3, 0x58, 0xd8, 0x02, 0x6c, 0x5e, 0xad, 0x79,
+ 0xde, 0x77, 0x1a, 0xd3, 0x49, 0xc9, 0x12, 0xc9,
+ 0xff, 0xcf, 0xa2, 0x6c, 0x1d, 0x37, 0x91, 0xa2,
+ 0xf5, 0x43, 0xbc, 0xdb, 0x9e, 0xdb, 0xa5, 0xdb,
+ 0xd9, 0x87, 0xc5, 0xf2, 0xf7, 0x79, 0x58, 0x4c,
+ 0x08, 0x9f, 0x9c, 0xca, 0x9c, 0xef, 0xa8, 0x80,
+ 0x27, 0x31, 0xf1, 0xc5, 0x0e, 0x2b, 0x6d, 0xa1,
+ 0x53, 0x9e, 0x99, 0x1e, 0xc8, 0x75, 0x4a, 0x59,
+ 0x27, 0x33, 0x41, 0xdd, 0x39, 0xff, 0x37, 0xdf,
+ 0x5b, 0xb9, 0xe4, 0x56, 0x54, 0x28, 0x8e, 0xb1,
+ 0xfe, 0xd8, 0x4e, 0x60, 0xcd, 0x22, 0xd7, 0x30,
+ 0xe5, 0x73, 0xe4, 0xb1, 0x08, 0x0f, 0x0a, 0xbe,
+ 0x9a, 0x44, 0xfd, 0xb1, 0xed, 0xb1, 0x8e, 0x0d,
+ 0x7c, 0x3c, 0x3d, 0x04, 0x52, 0x4b, 0x93, 0xf4,
+ 0xa6, 0xce, 0x8d, 0xb0, 0xe4, 0xf6, 0xb1, 0x09,
+ 0xfc, 0xc3, 0x42, 0x3d, 0xff, 0x4c, 0x55, 0x3c,
+ 0x73, 0x75, 0x35, 0x9d, 0xe8, 0x68, 0x42, 0x09,
+ 0x14, 0x36, 0x91, 0x63, 0xfc, 0xc6, 0x23, 0x7c,
+ 0x25, 0x81, 0xd5, 0xc1, 0xfe, 0xca, 0xf6, 0x71,
+ 0x51, 0x8e, 0xab, 0x29, 0xa1, 0x86, 0xbb, 0x45,
+ 0x43, 0x67, 0x7f, 0xdf, 0x7e, 0x92, 0xff, 0x35,
+ 0x38, 0xd3, 0xea, 0x94, 0xc9, 0xa3, 0x0f, 0x46,
+ 0x25, 0xa6, 0x1e, 0x00, 0x60, 0x7b, 0xc0, 0xbc,
+ 0xe9, 0x5e, 0x16, 0x0e, 0x81, 0xf5, 0x4e, 0x98,
+ 0xa1, 0x64, 0xb0, 0xb7, 0x02, 0xec, 0x73, 0xad,
+ 0xf8, 0xc1, 0xce, 0x8b, 0x8f, 0xbd, 0x89, 0xbf,
+ 0x0f, 0x42, 0x31, 0x6d, 0x75, 0x42, 0xd7, 0x59,
+ 0x64, 0xad, 0x09, 0xd3, 0x7a, 0x00, 0x7b, 0xdd,
+ 0x12, 0x76, 0xb0, 0x00, 0x73, 0x5b, 0xbf, 0x44,
+ 0x54, 0x6e, 0x56, 0x26, 0xa5, 0x27, 0x4d, 0xff,
+ 0xe5, 0x8a, 0x04, 0x73, 0xd9, 0x75, 0x8c, 0xf7,
+ 0x06, 0x64, 0xfb, 0xa5, 0x00, 0x27, 0x39, 0x0e,
+ 0x48, 0x8f, 0x73, 0x29, 0x61, 0x5f, 0x15, 0xf5,
+ 0x08, 0x15, 0x33, 0xd1, 0x76, 0xba, 0xf3, 0x3e,
+ 0x28, 0xb8, 0x57, 0xcd, 0x9d, 0x61, 0x1f, 0xca,
+ 0xd7, 0xc3, 0x10, 0xdb, 0x68, 0xeb, 0xa4, 0x15,
+ 0x40, 0xd8, 0xe7, 0xa0, 0xd2, 0xd1, 0xd6, 0xb1,
+ 0xd3, 0x75, 0x8e, 0xc1, 0x60, 0x02, 0xb5, 0x69,
+ 0xf2, 0x8c, 0xf3, 0xc6, 0x2e, 0x9d, 0xf7, 0x8d,
+ 0xed, 0xb0, 0x01, 0xba, 0xb5, 0x62, 0x7e, 0x8f,
+ 0x91, 0xbd, 0x73, 0xc6, 0x35, 0xf9, 0xdb, 0xea,
+ 0x28, 0xce, 0x8a, 0x47, 0x74, 0x7c, 0x3d, 0x85,
+ 0x4d, 0x1e, 0x11, 0x7e, 0xa2, 0xaa, 0x04, 0x30,
+ 0x12, 0xce, 0xea, 0xc1, 0xc5, 0x1e, 0x62, 0x7a,
+ 0x21, 0x6a, 0xd5, 0xb8, 0x3c, 0xa0, 0xd6, 0xca,
+ 0xb4, 0x8d, 0xff, 0xc3, 0xfc, 0xf2, 0xf1, 0x3c,
+ 0x87, 0x23, 0xef, 0x68, 0xe4, 0x37, 0x96, 0xb0,
+ 0xbb, 0x78, 0xa3, 0x3a, 0xe0, 0xd0, 0x41, 0xeb,
+ 0x4c, 0x80, 0x55, 0x9b, 0x66, 0x5e, 0x33, 0xea,
+ 0x33, 0x35, 0x79, 0xda, 0x04, 0x81, 0x19, 0x22,
+ 0xb4, 0x4c, 0x7a, 0xef, 0x51, 0x50, 0x20, 0x6c,
+ 0xf8, 0xf7, 0x5f, 0x03, 0x74, 0x72, 0xda, 0x1f,
+ 0xe3, 0x0b, 0x82, 0x71, 0x50, 0x3d, 0x02, 0x61,
+ 0x16, 0x44, 0xeb, 0xcf, 0xe3, 0x23, 0x9d, 0xef,
+ 0xec, 0xce, 0xb3, 0xd0, 0xd2, 0x19, 0xd1, 0xe0,
+ 0x2e, 0x33, 0xde, 0x28, 0x4b, 0xde, 0x85, 0xc1,
+ 0xb2, 0x8a, 0xa5, 0x82, 0x0c, 0xa6, 0x9f, 0x23,
+ 0x53, 0xea, 0xef, 0x78, 0x60, 0x24, 0x3a, 0x40,
+ 0xc0, 0xc1, 0xac, 0xc9, 0x64, 0xd4, 0x03, 0x5f,
+ 0x61, 0xa5, 0xdf, 0x6f, 0x6b, 0x4e, 0xb2, 0xe7,
+ 0x1a, 0xc6, 0x69, 0x69, 0xd9, 0xc6, 0x6e, 0x5d,
+ 0xea, 0xd8, 0xc0, 0x29, 0xcc, 0x8f, 0x35, 0x7b,
+ 0xcb, 0x48, 0x3a, 0xfd, 0xba, 0x7a, 0x90, 0xc7,
+ 0x65, 0x55, 0xfc, 0x90, 0x98, 0x6c, 0x15, 0x38,
+ 0x0e, 0x88, 0x6e, 0x08, 0x49, 0x85, 0xc6, 0x6d,
+ 0x8f, 0x30, 0x37, 0xa1, 0x64, 0x79, 0xa1, 0x65,
+ 0x2d, 0x07, 0x38, 0x3e, 0x1c, 0xa6, 0x12, 0xee,
+ 0xc5, 0x16, 0x68, 0x5c, 0x93, 0x14, 0xda, 0x33,
+ 0x3d, 0x74, 0x62, 0xf1, 0xcf, 0x0e, 0x81, 0x80,
+ 0xda, 0xea, 0xa7, 0x08, 0xde, 0xf3, 0xdc, 0xfe,
+ 0x3a, 0xf5, 0x60, 0xe9, 0x35, 0x95, 0x52, 0x6c,
+ 0x7f, 0xef, 0x8b, 0xa7, 0x55, 0x3d, 0x42, 0xfd,
+ 0x39, 0x24, 0xd2, 0xfb, 0x28, 0x08, 0x83, 0x2b,
+ 0x44, 0xf1, 0x21, 0x73, 0x13, 0x88, 0xa7, 0xba,
+ 0x2d, 0xd6, 0xe9, 0x4e, 0xcb, 0xfe, 0x18, 0xe4,
+ 0xc7, 0x85, 0xf3, 0xb8, 0xab, 0xd0, 0xb9, 0xbe,
+ 0x5e, 0x8a, 0x62, 0x0e, 0x61, 0xa3, 0x29, 0x1d,
+ 0xef, 0x46, 0xe7, 0x70, 0x14, 0xb1, 0x9f, 0x07,
+ 0xbf, 0x3f, 0x1f, 0xc8, 0x11, 0xe4, 0x2c, 0x39,
+ 0x48, 0x0e, 0xcf, 0x92, 0x62, 0x4b, 0x1f, 0x0c,
+ 0x2e, 0x29, 0x61, 0xef, 0x29, 0x67, 0x7c, 0x0f,
+ 0xac, 0x99, 0xb2, 0x9a, 0x7d, 0xac, 0x7c, 0x54,
+ 0xae, 0xed, 0x4b, 0xf5, 0x4a, 0x4b, 0xb4, 0x14,
+ 0xad, 0x6d, 0xce, 0xce, 0xcc, 0x3f, 0xb8, 0x59,
+ 0x71, 0x7c, 0xd4, 0x76, 0x7c, 0xe4, 0x68, 0xc6,
+ 0x76, 0xa8, 0xe3, 0x03, 0x48, 0xb6, 0xe4, 0x11,
+ 0x6c, 0x5f, 0xd4, 0x76, 0x80, 0xdf, 0x2c, 0x67,
+ 0x00, 0x4c, 0xce, 0x22, 0x21, 0xff, 0xb0, 0x9b,
+ 0xcb, 0x72, 0xd1, 0xe3, 0xa2, 0x32, 0x5c, 0x12,
+ 0xda, 0x7c, 0x95, 0x5d, 0xb2, 0xae, 0x1b, 0x25,
+ 0x2e, 0x5f, 0xe6, 0xff, 0x4c, 0xbf, 0x00, 0x16,
+ 0xd0, 0x3c, 0xbf, 0x44, 0x92, 0x07, 0xa0, 0x0d,
+ 0x13, 0xba, 0xb8, 0x62, 0x66, 0x0b, 0x14, 0x0f,
+ 0x5a, 0x9d, 0x42, 0x19, 0xd7, 0xbe, 0xe3, 0x33,
+ 0x53, 0xa2, 0x60, 0x2d, 0xde, 0x43, 0x85, 0x03,
+ 0x96, 0x50, 0x83, 0x83, 0x25, 0x3c, 0x19, 0x20,
+ 0x44, 0x5f, 0x3b, 0x5a, 0xc2, 0x90, 0xe1, 0x2d,
+ 0x47, 0x53, 0x50, 0xeb, 0xf7, 0xc7, 0x46, 0x4c,
+ 0xf2, 0xad, 0xb2, 0x8f, 0x03, 0x4e, 0x82, 0x5d,
+ 0x0f, 0xa0, 0x3d, 0xde, 0x4d, 0x93, 0x34, 0xd0,
+ 0x1a, 0xe2, 0x5d, 0xbc, 0xe5, 0x8d, 0xfb, 0x5a,
+ 0xba, 0xe2, 0x24, 0xec, 0xc8, 0xd2, 0xa3, 0x91,
+ 0xa2, 0xa9, 0x0e, 0x0e, 0xf5, 0xfb, 0x9f, 0xed,
+ 0x69, 0x21, 0x9d, 0x00, 0x92, 0xb5, 0x94, 0x0f,
+ 0x38, 0x94, 0x29, 0xf9, 0xe7, 0xaa, 0xf1, 0xf7,
+ 0x20, 0x10, 0xf0, 0xeb, 0x26, 0x96, 0x5a, 0x0e,
+ 0x99, 0x8d, 0x71, 0xef, 0xb2, 0xa0, 0xf3, 0x38,
+ 0xce, 0xf9, 0x99, 0x6f, 0x96, 0xbb, 0xa5, 0x55,
+ 0x27, 0x5c, 0xf5, 0xf8, 0x63, 0xf7, 0xf8, 0x0a,
+ 0x31, 0xee, 0x01, 0xa8, 0xc9, 0x0c, 0xbd, 0x73,
+ 0x62, 0x21, 0xa7, 0x1c, 0xd1, 0x62, 0xe5, 0xdd,
+ 0x43, 0x95, 0x4d, 0x60, 0x11, 0x65, 0x6c, 0xfa,
+ 0x67, 0x9a, 0x2f, 0x24, 0x1e, 0xbd, 0x10, 0xc4,
+ 0xe5, 0x23, 0x6f, 0x02, 0x76, 0x51, 0xd6, 0xe3,
+ 0xad, 0x88, 0xda, 0xc4, 0xd9, 0x6a, 0x8f, 0xf7,
+ 0xd2, 0x50, 0xdf, 0x9a, 0xad, 0x21, 0xc7, 0x5b,
+ 0x47, 0x83, 0xf6, 0xc8, 0xcb, 0x0a, 0xd5, 0x28,
+ 0x91, 0x3f, 0x18, 0x44, 0x62, 0x81, 0xfb, 0xcf,
+ 0x51, 0x5d, 0xa1, 0xf5, 0x46, 0x74, 0x0d, 0x32,
+ 0x21, 0x55, 0x1b, 0x8a, 0xf3, 0xd0, 0x4f, 0x41,
+ 0x86, 0xc3, 0x55, 0x0b, 0x1c, 0xd9, 0x56, 0x2f,
+ 0xcf, 0xe7, 0x9f, 0x06, 0x73, 0x82, 0xc2, 0x30,
+ 0x7a, 0xc2, 0x01, 0xa2, 0x1e, 0xeb, 0x5d, 0x77,
+ 0x7f, 0xbe, 0xee, 0xf4, 0x8a, 0x1b, 0x3b, 0xe3,
+ 0x2d, 0xd5, 0x3e, 0x3b, 0x40, 0x82, 0xd6, 0x60,
+ 0x86, 0x2f, 0xe9, 0xac, 0xc3, 0x65, 0xa5, 0xa3,
+ 0x8c, 0x54, 0x51, 0x1f, 0x8e, 0x89, 0x19, 0xdd,
+ 0xc5, 0x4a, 0xc0, 0xa2, 0x8b, 0xe5, 0x80, 0xfd,
+ 0xa1, 0xd8, 0xe9, 0x15, 0xa0, 0x94, 0xd7, 0x9e,
+ 0xe2, 0xf1, 0x83, 0x52, 0xf3, 0x0e, 0x34, 0x2f,
+ 0x85, 0x67, 0x49, 0x73, 0x67, 0xb9, 0xb5, 0xd5,
+ 0x0c, 0x1d, 0x03, 0x8e, 0x68, 0x57, 0x8d, 0xd2,
+ 0x33, 0x44, 0x94, 0x28, 0x5b, 0xfa, 0xe0, 0x2b,
+ 0x80, 0xd9, 0x96, 0x85, 0x6e, 0x0a, 0x2a, 0xdd,
+ 0x9b, 0x5b, 0x55, 0x5a, 0x31, 0xb6, 0xfe, 0x3e,
+ 0x0a, 0x41, 0x28, 0x20, 0xa7, 0xde, 0x31, 0xbe,
+ 0x73, 0xcb, 0xbc, 0xbb, 0x50, 0xf8, 0x58, 0x74,
+ 0xb1, 0x6b, 0x3f, 0x9a, 0x6c, 0x5e, 0x02, 0x87,
+ 0x8d, 0x19, 0xa1, 0xd3, 0x6a, 0xc2, 0x91, 0x82,
+ 0x3e, 0x0c, 0x90, 0xb8, 0xa6, 0x95, 0x23, 0x4e,
+ 0xb9, 0x2d, 0x4d, 0x6c, 0xfb, 0xd7, 0x5e, 0xdf,
+ 0xca, 0x06, 0x9b, 0x94, 0xb7, 0xfc, 0xbc, 0xad,
+ 0x39, 0x5d, 0x43, 0xcb, 0x1c, 0x7d, 0x3c, 0x95,
+ 0x3f, 0xf4, 0x47, 0x04, 0x1f, 0xfc, 0x8b, 0x23,
+ 0xe7, 0xcf, 0x24, 0x6f, 0x40, 0x9b, 0xa5, 0x56,
+ 0xcd, 0x69, 0x9e, 0x1f, 0x5a, 0xa0, 0x3b, 0x8f,
+ 0x3e, 0x1c, 0xe7, 0x42, 0xc9, 0x66, 0xee, 0x99,
+ 0x13, 0xb1, 0x4f, 0x65, 0x86, 0xba, 0xf0, 0x87,
+ 0x81, 0x6f, 0x44, 0x08, 0xb4, 0x18, 0xac, 0xb6,
+ 0xd3, 0x96, 0x68, 0xd4, 0x88, 0x89, 0xf2, 0xa2,
+ 0xd6, 0x2f, 0xfe, 0x7e, 0x49, 0xb3, 0x9c, 0xc9,
+ 0xaf, 0xd9, 0x28, 0xa8, 0x96, 0xc9, 0x2d, 0x26,
+ 0x5b, 0xc7, 0xef, 0x66, 0x08, 0xd2, 0x38, 0x4f,
+ 0x10, 0xb3, 0x83, 0x15, 0xf6, 0x00, 0x83, 0x3f,
+ 0x20, 0xfe, 0xa8, 0x44, 0x6b, 0x62, 0x3b, 0x17,
+ 0x39, 0x2e, 0xec, 0x5e, 0x78, 0xbe, 0xec, 0x16,
+ 0x29, 0xa6, 0x79, 0x4c, 0x08, 0x75, 0xc8, 0x78,
+ 0x3e, 0xc0, 0x05, 0xe9, 0xbb, 0x47, 0x94, 0xae,
+ 0xaf, 0xa5, 0xbb, 0xb8, 0x47, 0x31, 0xf7, 0xe9,
+ 0xb8, 0x1e, 0x6c, 0xda, 0x26, 0xc5, 0xf3, 0x26,
+ 0x89, 0xd5, 0x04, 0x23, 0x0b, 0x11, 0x84, 0x8f,
+};
+
+uint8_t mldsa_44_sign[] = {
+ 0x3E, 0xDD, 0xD2, 0x34, 0x62, 0x78, 0xEC, 0x19,
+ 0x9F, 0xAA, 0xEC, 0x89, 0x99, 0x78, 0x31, 0xCB,
+ 0x82, 0x0B, 0xE6, 0x46, 0x8D, 0x24, 0x9A, 0xD3,
+ 0x69, 0xB7, 0x01, 0x85, 0x93, 0x75, 0xD0, 0xBE,
+ 0xEA, 0x1F, 0x76, 0xFB, 0xB4, 0x6D, 0xC9, 0x64,
+ 0xD4, 0x44, 0x68, 0x5D, 0xAD, 0x09, 0x69, 0xFC,
+ 0x31, 0x2F, 0xD1, 0xFA, 0xEF, 0xF2, 0x1D, 0x2E,
+ 0xB6, 0xA5, 0xA9, 0xFD, 0x31, 0x04, 0x68, 0x1E,
+ 0x0B, 0xEC, 0xF4, 0x23, 0x4C, 0x9F, 0xC9, 0xD6,
+ 0x27, 0x8D, 0xE1, 0xAA, 0x29, 0x38, 0x16, 0x65,
+ 0x7E, 0x38, 0x5A, 0x30, 0xFC, 0xD9, 0xBF, 0x63,
+ 0x3B, 0x82, 0xFE, 0x0D, 0x68, 0xD4, 0x52, 0x55,
+ 0xBE, 0x86, 0x69, 0xCF, 0x75, 0x26, 0x2C, 0xB9,
+ 0x1D, 0x66, 0x39, 0x4C, 0x89, 0xAC, 0x36, 0xBF,
+ 0x34, 0x27, 0xCC, 0x7E, 0x6C, 0xC5, 0xBB, 0xFB,
+ 0x78, 0x03, 0x39, 0x61, 0xD8, 0x76, 0x63, 0x6E,
+ 0x6B, 0x68, 0x02, 0x43, 0x44, 0x57, 0x2E, 0x39,
+ 0x9E, 0x9D, 0x64, 0x77, 0x8E, 0x8B, 0x79, 0x36,
+ 0xCE, 0xE6, 0xBC, 0x6D, 0x80, 0xC8, 0x04, 0x81,
+ 0x2A, 0x04, 0xD4, 0xEF, 0x63, 0xE1, 0x3F, 0xC4,
+ 0xC1, 0x54, 0xD5, 0xAB, 0xE4, 0xEC, 0x65, 0xB0,
+ 0xF0, 0x1A, 0xB2, 0x32, 0x9A, 0xB8, 0x51, 0xD4,
+ 0x43, 0xFE, 0x81, 0x4F, 0xBD, 0x5D, 0xEE, 0xDE,
+ 0x24, 0xAC, 0xBC, 0x22, 0x9B, 0x80, 0xB7, 0xE8,
+ 0x22, 0x4B, 0x1B, 0x23, 0x89, 0x8C, 0xFE, 0xE3,
+ 0x30, 0x35, 0xA2, 0x0B, 0x4E, 0x66, 0x64, 0xFE,
+ 0x57, 0x68, 0xCF, 0xF5, 0xE5, 0x11, 0xB9, 0xB6,
+ 0x3A, 0x2B, 0x15, 0x0D, 0xA4, 0x11, 0xE1, 0x01,
+ 0x96, 0x06, 0x5D, 0x47, 0xCC, 0x04, 0x63, 0xB3,
+ 0xC7, 0xDD, 0x0F, 0x4A, 0x0A, 0x90, 0x9C, 0x0C,
+ 0x61, 0x1D, 0x4C, 0x21, 0x32, 0xD6, 0xE9, 0xDD,
+ 0x0F, 0x91, 0xA4, 0xD1, 0x30, 0x14, 0x1C, 0x48,
+ 0xEC, 0xF4, 0x4F, 0x02, 0x7B, 0x1E, 0x25, 0x3A,
+ 0x7C, 0x6B, 0x42, 0x13, 0xF7, 0xBC, 0xB5, 0x02,
+ 0xA9, 0x20, 0x85, 0x21, 0x01, 0x67, 0xC3, 0xDD,
+ 0x6C, 0x6D, 0xD3, 0xC9, 0x6F, 0x13, 0x75, 0xDD,
+ 0x1D, 0xD7, 0xE7, 0xF3, 0x34, 0x17, 0x37, 0xFF,
+ 0xE6, 0x3B, 0xB5, 0x1F, 0xEE, 0x51, 0x73, 0x6D,
+ 0x9E, 0xB7, 0xE2, 0xE7, 0xA1, 0x65, 0xE4, 0x29,
+ 0x8E, 0xBF, 0x66, 0xCE, 0x5E, 0xD4, 0xBA, 0x0C,
+ 0x18, 0x84, 0xBE, 0xAE, 0x9A, 0x17, 0x0D, 0xAE,
+ 0x55, 0x90, 0x7F, 0x72, 0x73, 0xAB, 0x9F, 0x87,
+ 0xCC, 0x3D, 0xCB, 0xE4, 0x38, 0x66, 0x92, 0xEE,
+ 0x6D, 0xE9, 0x0B, 0x8A, 0xE2, 0x5F, 0x68, 0x9D,
+ 0x06, 0xFD, 0xF3, 0x77, 0x4B, 0x50, 0xCD, 0x0E,
+ 0x2B, 0xE1, 0xD3, 0xB4, 0xF4, 0x02, 0xF5, 0x9B,
+ 0x5F, 0x3E, 0x59, 0xD7, 0x57, 0x9D, 0x87, 0x80,
+ 0x60, 0xEB, 0x70, 0xF5, 0x34, 0x56, 0x46, 0x5B,
+ 0xBA, 0x8F, 0x90, 0xAE, 0x9F, 0x6B, 0x43, 0x8C,
+ 0x51, 0x45, 0xD2, 0x16, 0x4C, 0xBA, 0x86, 0xF0,
+ 0xF4, 0xD5, 0x34, 0x6A, 0x3E, 0x5F, 0xAE, 0xBE,
+ 0x95, 0x40, 0xFE, 0x26, 0x4D, 0x5E, 0x60, 0x4E,
+ 0xD9, 0xEB, 0x47, 0x7D, 0x43, 0x63, 0x5F, 0x4B,
+ 0xB1, 0xCE, 0x7E, 0xA2, 0xF0, 0xC9, 0x30, 0x0C,
+ 0xB7, 0x13, 0x43, 0xC0, 0xF8, 0x02, 0x6C, 0xD2,
+ 0x5F, 0xCE, 0x25, 0xF3, 0xAE, 0xC3, 0x2D, 0xC3,
+ 0x13, 0xAE, 0x49, 0x8B, 0x82, 0x82, 0x44, 0xD0,
+ 0x50, 0xF8, 0x00, 0x5E, 0xAC, 0xDE, 0x4B, 0x88,
+ 0xC2, 0x38, 0x5C, 0xC3, 0x65, 0xF4, 0x25, 0x63,
+ 0x29, 0xC3, 0xB0, 0x7A, 0x45, 0x5D, 0x43, 0x89,
+ 0xCA, 0x5A, 0x12, 0x61, 0xD8, 0x92, 0x65, 0x1B,
+ 0x0F, 0xBF, 0x62, 0xB9, 0xA6, 0xF2, 0xA8, 0xA7,
+ 0x06, 0xAC, 0x02, 0xA4, 0xC6, 0x25, 0xD6, 0xC5,
+ 0xD2, 0xDE, 0x87, 0x88, 0x11, 0xBD, 0x7C, 0x87,
+ 0x91, 0xA9, 0x91, 0x60, 0x1F, 0x0F, 0xF0, 0x24,
+ 0xFE, 0xA0, 0xEB, 0xDC, 0x89, 0x68, 0x84, 0x10,
+ 0xD7, 0x55, 0xC1, 0x3A, 0xCA, 0x1F, 0xFF, 0x77,
+ 0x41, 0xA1, 0xDB, 0x13, 0x31, 0xEF, 0x9C, 0xA3,
+ 0xA2, 0x3A, 0x37, 0x1B, 0xF9, 0x46, 0xF8, 0x51,
+ 0x15, 0xB3, 0x0A, 0x12, 0x64, 0x3F, 0xE5, 0xA8,
+ 0x07, 0xA2, 0x57, 0x87, 0x2A, 0x3F, 0xD2, 0x87,
+ 0xDB, 0xC0, 0x33, 0xAC, 0xF5, 0x28, 0x42, 0xC5,
+ 0xD4, 0x20, 0x27, 0xAE, 0x57, 0xAF, 0x6C, 0x74,
+ 0x8A, 0xA0, 0x90, 0xEE, 0x34, 0xE9, 0x19, 0xB9,
+ 0x0E, 0xDF, 0x4D, 0xDE, 0x77, 0x66, 0xC4, 0xBC,
+ 0x99, 0x59, 0x14, 0xCB, 0x9D, 0xBF, 0xBC, 0x5F,
+ 0xFF, 0x2B, 0xA7, 0xED, 0x29, 0x49, 0x13, 0x6C,
+ 0x2B, 0x71, 0x58, 0xC2, 0xC4, 0x67, 0xCB, 0x6A,
+ 0x18, 0x6F, 0x4E, 0x88, 0xB9, 0x76, 0xC8, 0x6B,
+ 0xDC, 0x6A, 0x05, 0xA5, 0x22, 0x31, 0x15, 0xCE,
+ 0x54, 0xDA, 0xE8, 0x0E, 0xED, 0xDF, 0x46, 0x90,
+ 0x93, 0x9A, 0xE6, 0x2B, 0x45, 0xA4, 0x51, 0x42,
+ 0x29, 0x05, 0xA9, 0xFF, 0x29, 0xBE, 0x4F, 0x6E,
+ 0xE7, 0x52, 0x2C, 0x16, 0x3F, 0x95, 0x94, 0x7B,
+ 0xE6, 0xE1, 0xF7, 0x9F, 0x36, 0x1F, 0xEE, 0x46,
+ 0xA9, 0xE3, 0x71, 0x37, 0x08, 0xF7, 0x63, 0xAF,
+ 0x16, 0xB9, 0x43, 0x86, 0xAC, 0xC7, 0x5D, 0x5B,
+ 0x73, 0x38, 0x08, 0x2C, 0xC6, 0x65, 0x02, 0xC8,
+ 0x70, 0x71, 0x01, 0xA7, 0xD3, 0xA6, 0xB9, 0x74,
+ 0xAA, 0x71, 0x3B, 0x1B, 0xEF, 0x84, 0xA9, 0x77,
+ 0x91, 0x82, 0x7F, 0xB7, 0x3D, 0x2E, 0x8B, 0xD5,
+ 0x4D, 0xAD, 0x29, 0xAC, 0x51, 0x9E, 0xDB, 0xF0,
+ 0x4A, 0x1D, 0x29, 0x82, 0x04, 0x9E, 0x03, 0x8C,
+ 0x74, 0x66, 0x12, 0x75, 0xD0, 0x77, 0x07, 0xCC,
+ 0x7E, 0x8D, 0x19, 0x2F, 0x42, 0xFA, 0xB7, 0xBD,
+ 0x7E, 0x77, 0xEF, 0xF1, 0x35, 0xAF, 0x7C, 0xFF,
+ 0x52, 0x5F, 0xDB, 0x03, 0x99, 0x0D, 0x89, 0x8A,
+ 0x60, 0x61, 0x42, 0xC2, 0xE7, 0x33, 0x58, 0xE7,
+ 0x40, 0x90, 0x46, 0x84, 0xD5, 0x4B, 0x30, 0x88,
+ 0xA7, 0xBB, 0x25, 0xDE, 0x02, 0xFE, 0x57, 0x93,
+ 0xFD, 0xD0, 0x6E, 0xA2, 0xFE, 0x38, 0xA3, 0x5E,
+ 0x6C, 0x35, 0x06, 0xC4, 0xC6, 0x8C, 0x9C, 0x37,
+ 0x3B, 0x6A, 0x1D, 0x91, 0xCB, 0x84, 0x03, 0x47,
+ 0x85, 0xC7, 0x1D, 0x82, 0xEE, 0xB5, 0xF8, 0xEC,
+ 0x29, 0xDE, 0x30, 0x76, 0x32, 0x08, 0x6A, 0x75,
+ 0x43, 0x6A, 0xB8, 0x4C, 0x5D, 0x5A, 0x54, 0xC2,
+ 0xE3, 0x58, 0x43, 0x6E, 0x90, 0xCE, 0x51, 0xEB,
+ 0xE2, 0xFD, 0x68, 0xAE, 0xB3, 0xBA, 0x80, 0xB4,
+ 0x03, 0x84, 0x26, 0x4E, 0xAB, 0x7B, 0x15, 0x2D,
+ 0xDE, 0xB0, 0x7B, 0xF3, 0x4D, 0xFB, 0x6A, 0xFC,
+ 0xE3, 0x47, 0xFC, 0x9C, 0x34, 0xC8, 0xB2, 0x10,
+ 0x46, 0xCC, 0x5F, 0x0A, 0xC6, 0xEB, 0x48, 0x47,
+ 0xFF, 0x73, 0x75, 0xD0, 0x7C, 0xBF, 0x44, 0xCB,
+ 0xAE, 0x8A, 0x30, 0x0B, 0x3F, 0x58, 0x11, 0x51,
+ 0x32, 0xD5, 0x7C, 0xCC, 0xB5, 0xDB, 0xD9, 0x21,
+ 0xD0, 0x6C, 0x29, 0xE2, 0xD0, 0xE1, 0xB2, 0xC8,
+ 0x06, 0x29, 0xC0, 0xC8, 0x5B, 0xB2, 0x3A, 0x66,
+ 0x7A, 0x25, 0x13, 0x57, 0x80, 0x14, 0x5B, 0x31,
+ 0xC4, 0x7B, 0x21, 0xB5, 0x50, 0x9C, 0x76, 0x6B,
+ 0x8C, 0x16, 0xF7, 0x95, 0xA1, 0x79, 0x6B, 0xA8,
+ 0x22, 0x13, 0xD5, 0x32, 0x15, 0x3E, 0xFC, 0x55,
+ 0x80, 0xD2, 0x71, 0xD1, 0x59, 0x15, 0xDA, 0xFC,
+ 0x55, 0x75, 0xE7, 0x7E, 0x15, 0x48, 0xD9, 0x73,
+ 0x0D, 0x6A, 0x31, 0x8A, 0x1C, 0x86, 0x4A, 0x31,
+ 0x57, 0x5B, 0x0A, 0x9D, 0xE4, 0x8C, 0x80, 0x7F,
+ 0x0E, 0x07, 0x36, 0x38, 0x7C, 0xEA, 0x3C, 0xBD,
+ 0xBD, 0xD1, 0xAA, 0xE7, 0xE4, 0x43, 0xB2, 0xFC,
+ 0x26, 0x39, 0x4F, 0xCC, 0xE6, 0xB8, 0xD7, 0x90,
+ 0xC3, 0x5F, 0xAA, 0xEA, 0x78, 0xC6, 0xD7, 0x58,
+ 0x15, 0x7D, 0x27, 0xD0, 0x7E, 0x0F, 0x13, 0x0D,
+ 0x47, 0x49, 0x28, 0x5B, 0xD7, 0xBC, 0x41, 0xB5,
+ 0x66, 0x38, 0x29, 0xB4, 0x71, 0xEC, 0xA2, 0xDE,
+ 0xE3, 0xE0, 0x4C, 0x27, 0xB4, 0x2C, 0xEE, 0xF1,
+ 0x5F, 0x37, 0x81, 0xCE, 0x31, 0x42, 0x87, 0x44,
+ 0x39, 0x7B, 0x35, 0xCF, 0xE8, 0x7D, 0x5E, 0xD7,
+ 0xA3, 0x3D, 0xB9, 0x92, 0x95, 0x8C, 0x25, 0xC6,
+ 0xC9, 0xBC, 0x46, 0x4E, 0x03, 0x70, 0x29, 0x4B,
+ 0x79, 0xB8, 0xEF, 0x54, 0x98, 0x8B, 0x9A, 0x45,
+ 0x09, 0x8C, 0x43, 0xD1, 0x9B, 0x29, 0xEA, 0xDE,
+ 0xF2, 0x25, 0x10, 0xA6, 0xF9, 0x2C, 0xC8, 0x90,
+ 0x49, 0xA5, 0x3C, 0xDC, 0xCE, 0xA3, 0x98, 0xF1,
+ 0x4C, 0xC6, 0x3E, 0xE0, 0x21, 0x58, 0x1A, 0x39,
+ 0xDA, 0x50, 0x2A, 0x6A, 0x18, 0x49, 0xC9, 0xA1,
+ 0x9D, 0xF3, 0xF4, 0xFB, 0xDD, 0x6F, 0x8D, 0xF4,
+ 0xFE, 0x61, 0xA0, 0xC6, 0xF5, 0x58, 0x89, 0xAE,
+ 0xEC, 0xC6, 0xE0, 0x88, 0x4A, 0x07, 0x6F, 0x11,
+ 0x72, 0x5A, 0x6D, 0x3E, 0x08, 0x64, 0x3E, 0x23,
+ 0x7D, 0x9A, 0x74, 0xB3, 0xC3, 0xDA, 0xA7, 0x29,
+ 0x0E, 0xC1, 0x37, 0xB0, 0x04, 0x42, 0x47, 0x01,
+ 0x80, 0x4B, 0xC0, 0x35, 0x49, 0x19, 0xB1, 0xDB,
+ 0x51, 0x51, 0x09, 0x90, 0x08, 0xB2, 0xC4, 0x5C,
+ 0xA0, 0xD6, 0x6E, 0x09, 0xFF, 0xA0, 0xC6, 0x4F,
+ 0x32, 0x95, 0x84, 0xBE, 0xAA, 0x4A, 0x0A, 0x36,
+ 0x83, 0xD3, 0x0C, 0xB7, 0xE0, 0xD0, 0x24, 0xE9,
+ 0x0A, 0x2F, 0x0F, 0xB4, 0x3A, 0x2F, 0xCE, 0x34,
+ 0xE5, 0xF0, 0x67, 0x07, 0x72, 0x52, 0x24, 0xE9,
+ 0x9F, 0xBF, 0xDE, 0x40, 0x95, 0xAD, 0x74, 0x41,
+ 0x4A, 0x00, 0x07, 0xEB, 0x14, 0xDD, 0xC4, 0xA2,
+ 0x37, 0x72, 0x83, 0xE7, 0xD6, 0x20, 0xF5, 0xC6,
+ 0x86, 0x97, 0xC5, 0x64, 0x58, 0x1B, 0x57, 0x5F,
+ 0x9D, 0x06, 0x1D, 0xB5, 0x2D, 0x26, 0xBA, 0xE4,
+ 0x49, 0x71, 0x08, 0xBD, 0x21, 0xC4, 0xA9, 0xF3,
+ 0x26, 0x7A, 0x28, 0xD6, 0x81, 0x20, 0xCD, 0x9C,
+ 0xED, 0xB8, 0xDC, 0x45, 0x33, 0xC0, 0x54, 0x5C,
+ 0x3A, 0xF5, 0xC5, 0x1B, 0x19, 0x10, 0xCA, 0xDF,
+ 0x99, 0xD4, 0xEE, 0x25, 0xD6, 0x71, 0x24, 0x4D,
+ 0xFF, 0x14, 0x85, 0x58, 0x07, 0xC8, 0x3F, 0xD6,
+ 0x55, 0x1C, 0xBF, 0xF8, 0x94, 0x31, 0x04, 0x83,
+ 0xEC, 0xD1, 0xF5, 0x20, 0x72, 0xC3, 0xE9, 0xB1,
+ 0x8A, 0x00, 0x0B, 0x94, 0x53, 0x4C, 0x01, 0x8C,
+ 0xDE, 0x80, 0x59, 0x66, 0x72, 0x2D, 0xC5, 0x78,
+ 0xAC, 0x4A, 0xAD, 0x4F, 0x14, 0xC1, 0x78, 0x87,
+ 0x5F, 0xDF, 0xF2, 0x95, 0xCF, 0x8F, 0x3F, 0xA6,
+ 0xCC, 0xAA, 0x1E, 0xD8, 0xA8, 0x37, 0xAD, 0x5B,
+ 0xA5, 0x6D, 0xBC, 0x81, 0xAC, 0xCD, 0xFD, 0x56,
+ 0x9E, 0x8B, 0xB9, 0xEC, 0x7E, 0x82, 0x4E, 0x55,
+ 0x05, 0xFD, 0x9F, 0xDC, 0x0A, 0xF7, 0xBD, 0x3F,
+ 0xEA, 0x42, 0x9D, 0x7E, 0xAB, 0x09, 0xDF, 0x3D,
+ 0xA3, 0x8C, 0x63, 0x78, 0x81, 0x8F, 0x46, 0x9F,
+ 0x12, 0xB8, 0x8A, 0xA5, 0xE4, 0xE9, 0x73, 0x95,
+ 0x37, 0xD3, 0x39, 0xFE, 0x9B, 0x69, 0x58, 0x05,
+ 0x5B, 0x30, 0x09, 0x31, 0x8B, 0xD9, 0xDB, 0xAE,
+ 0x96, 0x93, 0x96, 0xDF, 0xC0, 0x70, 0x1D, 0xFF,
+ 0x5D, 0x60, 0x72, 0x5A, 0xDD, 0xC2, 0x3D, 0xCF,
+ 0x13, 0xA0, 0x36, 0x38, 0xF4, 0x3A, 0x03, 0x15,
+ 0x48, 0xF0, 0xB1, 0x4A, 0x12, 0x72, 0xBA, 0x6B,
+ 0xE2, 0xD6, 0x4E, 0x57, 0x22, 0x87, 0x2F, 0xE7,
+ 0x40, 0x1B, 0x22, 0xF3, 0x4A, 0xE7, 0xB1, 0xA4,
+ 0x28, 0xC7, 0xBB, 0x17, 0x5E, 0x0C, 0x03, 0xE3,
+ 0xF4, 0x67, 0x25, 0xB2, 0xBB, 0xE6, 0x4E, 0xCD,
+ 0x8A, 0x39, 0xC6, 0x05, 0xB7, 0x14, 0x10, 0xF4,
+ 0x36, 0xE9, 0x8A, 0xC3, 0x41, 0xD3, 0x30, 0xAD,
+ 0x79, 0x56, 0xE2, 0xC3, 0x55, 0xFC, 0x05, 0x3B,
+ 0xD0, 0x83, 0x31, 0xE7, 0xA1, 0x85, 0xBE, 0x6C,
+ 0xAF, 0x9D, 0xA6, 0x26, 0xC4, 0x7A, 0x4B, 0xD8,
+ 0x26, 0xA7, 0x59, 0xBB, 0x8D, 0x6E, 0x15, 0x96,
+ 0x84, 0x08, 0x0B, 0xDF, 0x29, 0x2D, 0x74, 0xD9,
+ 0xAD, 0xFE, 0xC1, 0x3A, 0x84, 0x4E, 0xCE, 0x8F,
+ 0x00, 0x9A, 0x50, 0xB8, 0x6F, 0x02, 0xE6, 0xEC,
+ 0xA9, 0xE6, 0x1F, 0x71, 0x6A, 0x48, 0x98, 0x61,
+ 0x3B, 0xC1, 0x37, 0x5A, 0x2E, 0xF3, 0xE0, 0xD6,
+ 0x11, 0x0C, 0x15, 0x39, 0x7B, 0xFB, 0x37, 0xAF,
+ 0x7A, 0xCA, 0xD6, 0x10, 0xDE, 0x95, 0x6A, 0xC6,
+ 0x19, 0xEC, 0x21, 0x51, 0xCE, 0xAE, 0x8F, 0x5A,
+ 0xEE, 0xEF, 0xB2, 0x9C, 0xF7, 0x4F, 0x5A, 0xB4,
+ 0x90, 0xED, 0xB0, 0x64, 0x59, 0x95, 0xC5, 0x32,
+ 0xC1, 0x85, 0xD7, 0x7E, 0x6C, 0xC6, 0x76, 0x11,
+ 0x4B, 0xB5, 0x17, 0x1D, 0xEE, 0x15, 0xFF, 0xD3,
+ 0xC7, 0xBB, 0xAA, 0x3C, 0x5D, 0x4D, 0x03, 0x82,
+ 0xC0, 0xC7, 0xEA, 0xD0, 0xD8, 0x1B, 0xFF, 0x3C,
+ 0x1D, 0x5A, 0x3F, 0xBD, 0x81, 0x66, 0x62, 0x6E,
+ 0xB3, 0xF5, 0x5F, 0xF0, 0x43, 0x90, 0x01, 0x71,
+ 0xDD, 0xB6, 0x0F, 0x60, 0xCE, 0xFB, 0x17, 0x21,
+ 0x5A, 0x7F, 0x0C, 0x69, 0x82, 0x9D, 0x4C, 0xF3,
+ 0x30, 0x1A, 0xF7, 0x1E, 0x85, 0x1A, 0x89, 0x84,
+ 0xF3, 0x4E, 0x8F, 0x15, 0x60, 0x43, 0x6D, 0x3A,
+ 0x5B, 0x07, 0xC0, 0x78, 0x6A, 0x02, 0xB4, 0x98,
+ 0x3D, 0xAB, 0xAC, 0x25, 0x55, 0xC8, 0x49, 0x7E,
+ 0xC9, 0x04, 0x73, 0xAF, 0x0D, 0x17, 0x1A, 0xA6,
+ 0xBE, 0xD8, 0x11, 0x69, 0x4F, 0x17, 0x39, 0xF3,
+ 0x57, 0x53, 0x1F, 0xD5, 0x1B, 0x15, 0x89, 0x53,
+ 0x54, 0xB1, 0x9F, 0xFD, 0x52, 0x92, 0xA8, 0x98,
+ 0xD4, 0x7B, 0xEE, 0x43, 0xC6, 0x31, 0xDE, 0xEC,
+ 0xDC, 0xE5, 0x1D, 0x90, 0x37, 0x63, 0xA1, 0xF8,
+ 0x42, 0x52, 0x8A, 0x73, 0x8B, 0x3D, 0x42, 0x85,
+ 0x64, 0x5C, 0xA9, 0xCC, 0xA1, 0xCD, 0xEB, 0x9E,
+ 0x2A, 0xF5, 0x21, 0x9E, 0x81, 0xC6, 0x2D, 0xD7,
+ 0x22, 0xC2, 0xEE, 0x47, 0x7E, 0xDA, 0x60, 0x26,
+ 0xFA, 0xE9, 0xB1, 0x81, 0x01, 0x77, 0xD3, 0x42,
+ 0xDD, 0x03, 0x65, 0x74, 0x2B, 0x85, 0x49, 0x9A,
+ 0xA5, 0x27, 0x76, 0x49, 0xF1, 0x72, 0x5E, 0xDF,
+ 0xB7, 0xAD, 0x19, 0x1A, 0x58, 0x89, 0x56, 0x5C,
+ 0x61, 0x03, 0xC7, 0x42, 0x84, 0xF2, 0x9E, 0x9E,
+ 0x09, 0x2A, 0x2D, 0x3B, 0xAE, 0x6A, 0x8E, 0x9A,
+ 0x87, 0x70, 0x16, 0x0A, 0xF1, 0xA9, 0xEA, 0xD2,
+ 0xF3, 0x2A, 0xA3, 0xB0, 0x32, 0xD3, 0x28, 0x92,
+ 0x19, 0x02, 0x77, 0xB2, 0x26, 0x1B, 0xC0, 0x59,
+ 0x1A, 0x67, 0x4B, 0x51, 0x04, 0x83, 0x25, 0xF6,
+ 0x4E, 0xA3, 0x92, 0x55, 0xCD, 0x74, 0xF5, 0x23,
+ 0x98, 0xB7, 0xB9, 0x75, 0xA6, 0xDC, 0x4E, 0xD2,
+ 0x93, 0x39, 0x94, 0xA3, 0xCD, 0xF8, 0xD5, 0xA4,
+ 0xA9, 0x3C, 0x97, 0xED, 0x18, 0x54, 0xBB, 0x59,
+ 0x7E, 0x75, 0xE3, 0xEE, 0x5A, 0x36, 0x53, 0x3D,
+ 0x02, 0xFB, 0x47, 0xE6, 0x10, 0x1D, 0xDF, 0x21,
+ 0xDA, 0x44, 0x66, 0x05, 0x81, 0xC4, 0xE9, 0x3B,
+ 0xD5, 0x56, 0xC5, 0xAD, 0x50, 0x7A, 0xE1, 0xAA,
+ 0x91, 0x7F, 0x7C, 0x4E, 0x85, 0xCC, 0xDC, 0x4A,
+ 0xBD, 0x72, 0x1F, 0x3F, 0x21, 0x93, 0x98, 0x21,
+ 0xB8, 0xCC, 0x21, 0x00, 0x24, 0x13, 0xAB, 0x63,
+ 0xC1, 0x31, 0xCA, 0x1C, 0x67, 0x0C, 0x0E, 0x5A,
+ 0x62, 0xC3, 0x1E, 0x6D, 0x63, 0x9B, 0xDA, 0x7F,
+ 0x92, 0xC4, 0x64, 0x8B, 0xC7, 0x80, 0x04, 0x05,
+ 0x36, 0x06, 0xCE, 0xF7, 0x37, 0x3A, 0xA8, 0xDF,
+ 0x2C, 0x61, 0x46, 0x48, 0x2A, 0x5C, 0xDC, 0xBB,
+ 0x34, 0x16, 0xDA, 0x59, 0x0D, 0x5B, 0xE5, 0x08,
+ 0x05, 0xAF, 0x59, 0x86, 0x34, 0x56, 0x88, 0x4F,
+ 0xAF, 0xA0, 0x28, 0xC4, 0xF2, 0x97, 0xC6, 0xF4,
+ 0x7C, 0xFD, 0xA4, 0x20, 0xE4, 0x20, 0x2C, 0xDA,
+ 0x98, 0xAD, 0x4A, 0x96, 0x9F, 0x62, 0xBB, 0x1C,
+ 0xB6, 0x28, 0xB0, 0xD0, 0xEA, 0x3B, 0xB8, 0x3C,
+ 0x8D, 0x4E, 0x97, 0xEA, 0x9E, 0x63, 0xAA, 0xAA,
+ 0x8D, 0x22, 0x61, 0x29, 0x1A, 0x82, 0x29, 0x86,
+ 0x87, 0x62, 0xA4, 0xE4, 0xC0, 0x03, 0x93, 0x55,
+ 0x7D, 0x40, 0xE9, 0x43, 0x14, 0x9C, 0xE2, 0xDA,
+ 0x0A, 0x00, 0x37, 0xEA, 0x80, 0xB8, 0x31, 0x66,
+ 0xAE, 0xD7, 0xF8, 0xB4, 0x24, 0xC7, 0x78, 0xDB,
+ 0x23, 0x66, 0x61, 0xA5, 0x47, 0x10, 0x4A, 0xE8,
+ 0x79, 0xB6, 0xBD, 0x6A, 0xB6, 0x22, 0x6C, 0x7B,
+ 0x19, 0xF3, 0x80, 0x35, 0x9A, 0x15, 0x36, 0x89,
+ 0x2A, 0x2C, 0xED, 0x26, 0xF1, 0x96, 0xFF, 0x30,
+ 0x4D, 0x03, 0x82, 0x2C, 0x69, 0x31, 0x40, 0x40,
+ 0x0C, 0xD1, 0x40, 0x3E, 0xE0, 0xB5, 0x37, 0xA8,
+ 0x6D, 0x68, 0x68, 0x8F, 0x9E, 0xC5, 0x12, 0x05,
+ 0xF5, 0x36, 0x85, 0x5F, 0x8A, 0x52, 0x7B, 0x60,
+ 0xA2, 0xC2, 0x39, 0xAF, 0x87, 0xC8, 0xC4, 0xF2,
+ 0x53, 0x1D, 0xF0, 0x84, 0x32, 0x8A, 0x04, 0x42,
+ 0xBF, 0xCA, 0x1A, 0x08, 0x89, 0x71, 0xCA, 0xC8,
+ 0x11, 0xA6, 0xDC, 0xED, 0x31, 0xFC, 0x41, 0xFC,
+ 0x84, 0x75, 0xA5, 0x98, 0x67, 0x9E, 0xE7, 0x69,
+ 0x9F, 0x3C, 0x42, 0x94, 0x69, 0xA5, 0x1D, 0xC2,
+ 0x55, 0x9D, 0x2E, 0xC9, 0x13, 0x3C, 0x68, 0x94,
+ 0xA9, 0x7E, 0x6A, 0xFC, 0x11, 0xE3, 0x97, 0x0D,
+ 0x59, 0x8F, 0x8D, 0x05, 0x01, 0x4A, 0x74, 0xB6,
+ 0x96, 0x6D, 0x1E, 0x7F, 0x63, 0xA5, 0x54, 0x39,
+ 0x5A, 0x6C, 0xB9, 0x9B, 0xC3, 0x79, 0xCB, 0xD3,
+ 0xC9, 0xE9, 0x37, 0x9E, 0xDC, 0x3B, 0xE2, 0xD2,
+ 0xE6, 0x07, 0x77, 0xFA, 0xD5, 0xCF, 0xD6, 0x42,
+ 0x45, 0x46, 0xFE, 0x06, 0x28, 0x0E, 0x4D, 0xA6,
+ 0x72, 0xE6, 0x6F, 0x39, 0xCD, 0xB9, 0xBF, 0x43,
+ 0xF7, 0xD9, 0x99, 0x9B, 0x46, 0xF1, 0x80, 0xBA,
+ 0x07, 0x4A, 0x0A, 0xC3, 0x9F, 0xD3, 0xCB, 0xA5,
+ 0x85, 0xF7, 0xEE, 0x9F, 0x6D, 0xC0, 0x52, 0xD7,
+ 0x17, 0x27, 0x81, 0x92, 0x98, 0xA0, 0xBB, 0xC9,
+ 0xD7, 0xE4, 0xF0, 0xF8, 0x25, 0x2C, 0x38, 0x3B,
+ 0x44, 0x4E, 0x55, 0x57, 0x5F, 0x86, 0x9A, 0xA1,
+ 0xB2, 0xBB, 0xBF, 0xE4, 0xF4, 0x04, 0x0D, 0x16,
+ 0x34, 0x48, 0x5A, 0x68, 0x72, 0x88, 0x8B, 0x97,
+ 0xA5, 0xAC, 0xBC, 0xC4, 0xC9, 0xCC, 0xF3, 0x03,
+ 0x12, 0x14, 0x2C, 0x3B, 0x3E, 0x3F, 0x4D, 0x52,
+ 0x79, 0x7A, 0x91, 0x96, 0xA8, 0xB3, 0xBB, 0xCC,
+ 0xCF, 0xD7, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0C, 0x1D, 0x2F, 0x43,
+};
+
+uint8_t mldsa_44_sign_dtrm[] = {
+ 0xC7, 0x9B, 0x98, 0x33, 0xEA, 0xCC, 0xCC, 0x47,
+ 0x51, 0x8F, 0xE1, 0xC0, 0xDA, 0x82, 0x9B, 0xAA,
+ 0x74, 0x0A, 0x14, 0x25, 0x73, 0x53, 0x27, 0x7C,
+ 0x4C, 0x4A, 0xD6, 0xB7, 0x7C, 0x71, 0x25, 0xD8,
+ 0xC5, 0xBA, 0xA8, 0x18, 0x59, 0xC7, 0x64, 0x2E,
+ 0x9A, 0x65, 0xE9, 0x63, 0x83, 0x3D, 0xB8, 0x2B,
+ 0x42, 0x0A, 0x6D, 0x7D, 0xCE, 0x6A, 0xA3, 0x11,
+ 0xD6, 0xB6, 0x54, 0x82, 0x36, 0x38, 0xF1, 0x84,
+ 0x01, 0x3E, 0x26, 0x66, 0xC7, 0x38, 0x6F, 0x41,
+ 0x4C, 0xC2, 0x42, 0xB5, 0xBF, 0xCE, 0x7B, 0x8B,
+ 0xD5, 0x4F, 0x9B, 0x9F, 0x0E, 0xFE, 0x52, 0xAF,
+ 0x6D, 0x39, 0xD8, 0x0A, 0x27, 0x4D, 0xDB, 0x9F,
+ 0x04, 0x25, 0x8C, 0xF5, 0x89, 0x5B, 0xEB, 0xDC,
+ 0x70, 0xBF, 0x23, 0x1D, 0x14, 0x73, 0x9E, 0xFC,
+ 0x41, 0xA0, 0xA2, 0xA5, 0xAA, 0xAB, 0x8E, 0xCD,
+ 0x5E, 0x29, 0xC5, 0x3E, 0xEC, 0x0A, 0xD9, 0x06,
+ 0xEB, 0x8C, 0x18, 0x41, 0x80, 0x91, 0x5D, 0xC9,
+ 0x28, 0xCE, 0xDB, 0x1C, 0x0E, 0x8F, 0xE3, 0xC0,
+ 0xE5, 0xB1, 0x0A, 0x38, 0x06, 0x43, 0x36, 0x0D,
+ 0xF8, 0xE6, 0x2E, 0xCB, 0xEB, 0x51, 0xC8, 0x82,
+ 0xE0, 0x3B, 0xCB, 0xCE, 0x62, 0xC8, 0xE0, 0x8A,
+ 0x2C, 0xE4, 0xC7, 0xD7, 0xC1, 0x8A, 0x64, 0x0D,
+ 0xE8, 0x5A, 0x52, 0x83, 0x58, 0x93, 0x2A, 0x25,
+ 0x92, 0x65, 0x19, 0x4F, 0x0F, 0x44, 0x1C, 0xCE,
+ 0x56, 0x91, 0xB4, 0xC9, 0x8D, 0x9E, 0x6A, 0xD5,
+ 0xCA, 0xE3, 0xA0, 0xE3, 0x46, 0x45, 0x0D, 0x59,
+ 0x14, 0x90, 0x72, 0x67, 0xC5, 0x95, 0xAC, 0x2A,
+ 0xC4, 0x70, 0xD2, 0xCA, 0x40, 0x1D, 0x62, 0x0E,
+ 0x2A, 0xA4, 0x3E, 0xAC, 0x45, 0x00, 0x96, 0xA4,
+ 0xF6, 0xAC, 0xEE, 0x01, 0x19, 0xEB, 0xCC, 0x8C,
+ 0x62, 0xE3, 0x26, 0x59, 0xB7, 0xB9, 0xBF, 0xBB,
+ 0x8D, 0x72, 0xAD, 0x1A, 0xA2, 0x8D, 0xB1, 0x1B,
+ 0xC1, 0xC1, 0xD8, 0xFF, 0x03, 0xAF, 0x74, 0xDF,
+ 0xC6, 0x3C, 0xCE, 0xBD, 0xA8, 0x12, 0xFA, 0xAC,
+ 0x83, 0x8C, 0x7E, 0x26, 0x8E, 0x0D, 0x03, 0xF3,
+ 0x02, 0x17, 0x23, 0x13, 0x25, 0x01, 0x1F, 0xB9,
+ 0x3B, 0x1C, 0x3E, 0xA7, 0xD9, 0xE4, 0xE6, 0xCA,
+ 0xD6, 0x0C, 0x91, 0xAC, 0xEE, 0xD4, 0x42, 0xA7,
+ 0xB1, 0x62, 0x70, 0xC8, 0xC9, 0x2F, 0x0A, 0xE0,
+ 0xA8, 0xC7, 0x22, 0xE5, 0x2C, 0x06, 0x1C, 0x09,
+ 0x4B, 0x45, 0x25, 0x02, 0x07, 0x8A, 0x86, 0xCC,
+ 0xF8, 0xF9, 0x36, 0x11, 0x67, 0x75, 0xEE, 0xD2,
+ 0xD4, 0x67, 0x09, 0xFD, 0x37, 0xB4, 0x3F, 0x7B,
+ 0x4A, 0x2B, 0x4E, 0x05, 0x37, 0x5E, 0xFD, 0x97,
+ 0x79, 0x95, 0x13, 0x95, 0x0D, 0x75, 0x15, 0x94,
+ 0x27, 0x36, 0xB3, 0x97, 0x03, 0xBE, 0x38, 0x14,
+ 0xCB, 0x4D, 0x16, 0x49, 0xFF, 0x36, 0xFA, 0xED,
+ 0x4D, 0x97, 0x45, 0xE4, 0xFB, 0xF9, 0x61, 0x7D,
+ 0x1F, 0xCE, 0xC3, 0xBF, 0xB3, 0xEA, 0x3C, 0xBC,
+ 0x13, 0x05, 0xBB, 0xAB, 0x44, 0x84, 0x80, 0x0F,
+ 0xB9, 0x1F, 0x6E, 0x88, 0x27, 0x4A, 0xFA, 0x17,
+ 0x83, 0x76, 0x5F, 0xC5, 0xE8, 0x85, 0xBC, 0xFF,
+ 0xD8, 0x48, 0x4A, 0x9F, 0xEB, 0xC3, 0xF8, 0x41,
+ 0x86, 0x4D, 0xC2, 0x75, 0x7B, 0x74, 0x71, 0x68,
+ 0x9C, 0xF8, 0x05, 0x8B, 0xB7, 0xFA, 0xE0, 0xA7,
+ 0xFA, 0xEC, 0x53, 0x91, 0xD0, 0xB4, 0x44, 0x7A,
+ 0x42, 0xAD, 0xD2, 0x17, 0x86, 0x8F, 0x96, 0xF0,
+ 0xF1, 0xD6, 0xC0, 0x26, 0x34, 0x83, 0x2E, 0x62,
+ 0x0D, 0x3F, 0x13, 0x5A, 0x8C, 0xBC, 0x6D, 0x8D,
+ 0x39, 0x05, 0x91, 0x10, 0x32, 0xBE, 0x17, 0x8A,
+ 0xC7, 0x23, 0xBE, 0x3F, 0xC5, 0x8A, 0xE0, 0x81,
+ 0xFC, 0x0D, 0x4C, 0x62, 0xE8, 0x67, 0xBA, 0x8B,
+ 0xBD, 0xA5, 0xCB, 0xE9, 0x34, 0x3D, 0x8D, 0x84,
+ 0x9D, 0x65, 0xBF, 0x9E, 0xC4, 0xB3, 0x16, 0x2E,
+ 0x12, 0xB9, 0x1F, 0x82, 0xA1, 0x46, 0x26, 0xD5,
+ 0xAB, 0x7D, 0x80, 0x4D, 0x9C, 0xD3, 0xEB, 0x77,
+ 0xFB, 0x67, 0xEA, 0xEE, 0xA8, 0x7B, 0x17, 0x02,
+ 0x2E, 0x6E, 0xF5, 0x11, 0x44, 0xFC, 0x31, 0x01,
+ 0xCC, 0x03, 0x94, 0x0A, 0xCF, 0x8D, 0x12, 0xCD,
+ 0x87, 0x66, 0x38, 0x62, 0x3C, 0xBB, 0x98, 0x2E,
+ 0xC5, 0x58, 0xD0, 0xF3, 0x06, 0xBD, 0x49, 0x7E,
+ 0x18, 0x7D, 0x64, 0xEF, 0x37, 0x71, 0x87, 0xD4,
+ 0xE6, 0x2C, 0xCC, 0x32, 0x59, 0x65, 0x05, 0x45,
+ 0xDE, 0xF3, 0x17, 0x62, 0x2C, 0x25, 0x62, 0x9C,
+ 0x67, 0xBD, 0x74, 0xF1, 0x54, 0x0E, 0x0B, 0x4A,
+ 0x01, 0x9F, 0x5E, 0x3B, 0x08, 0x57, 0xFA, 0x09,
+ 0x99, 0x11, 0x2C, 0x3E, 0x1D, 0x2D, 0xF7, 0x91,
+ 0x12, 0x14, 0xFF, 0x95, 0x6F, 0xCA, 0xBD, 0x25,
+ 0xEC, 0x3C, 0x98, 0xA7, 0xAB, 0x98, 0x0E, 0xFB,
+ 0x01, 0xE9, 0x5E, 0x58, 0x5A, 0x49, 0x3F, 0xB2,
+ 0xC4, 0xBC, 0xF3, 0xEC, 0xCA, 0x4C, 0x54, 0x27,
+ 0x66, 0x10, 0x60, 0x76, 0x5C, 0xFB, 0x9E, 0xAC,
+ 0xD2, 0x09, 0x75, 0xB3, 0x2B, 0x65, 0xE7, 0x93,
+ 0xAD, 0x2B, 0x08, 0x6F, 0x87, 0x73, 0x45, 0x2A,
+ 0x1B, 0xB1, 0x75, 0xE7, 0x02, 0x9B, 0xCB, 0x56,
+ 0x87, 0x6F, 0x66, 0x44, 0xED, 0xDC, 0x03, 0x92,
+ 0xD4, 0xF1, 0x07, 0x40, 0xD6, 0x86, 0xD5, 0x98,
+ 0x3D, 0x9B, 0x03, 0xD9, 0x0A, 0x58, 0x59, 0x54,
+ 0x06, 0x10, 0xFD, 0x15, 0xFB, 0xE0, 0x5B, 0x81,
+ 0x8D, 0x0C, 0xC0, 0xA6, 0x15, 0x94, 0x72, 0x5E,
+ 0xC8, 0x4A, 0x73, 0x59, 0x63, 0xF6, 0xCD, 0x8D,
+ 0xA4, 0xC2, 0xAF, 0x2E, 0xAE, 0xC1, 0x93, 0x89,
+ 0x08, 0x81, 0x10, 0xEC, 0x44, 0x81, 0x33, 0x96,
+ 0x88, 0xDC, 0x19, 0xDF, 0xD4, 0x2E, 0x5D, 0x52,
+ 0xD7, 0x6A, 0x02, 0x64, 0x11, 0x6B, 0x24, 0xCF,
+ 0x51, 0xD4, 0xC1, 0x85, 0x7D, 0xA3, 0x24, 0x6A,
+ 0x05, 0x13, 0x55, 0xC3, 0x64, 0x5A, 0xDF, 0x9A,
+ 0x23, 0x73, 0xEA, 0xD9, 0x48, 0x98, 0xBE, 0x1C,
+ 0xBD, 0x3A, 0x5D, 0x37, 0xDC, 0x18, 0xA8, 0x39,
+ 0x71, 0x67, 0xC4, 0x12, 0xF1, 0xE3, 0x53, 0x73,
+ 0xF1, 0xD8, 0xC4, 0x8B, 0xB3, 0x64, 0x03, 0xDD,
+ 0x6E, 0xFB, 0x4A, 0xEF, 0xA4, 0x37, 0xA8, 0xA5,
+ 0x2E, 0x86, 0x40, 0x73, 0x16, 0xBA, 0x3A, 0xF5,
+ 0x5E, 0x47, 0xD8, 0x13, 0x58, 0xB7, 0x73, 0xA2,
+ 0xDA, 0x00, 0x9F, 0x90, 0xE4, 0xF8, 0x0B, 0xB3,
+ 0x26, 0x0A, 0xD8, 0x46, 0x8A, 0x09, 0x55, 0xCB,
+ 0xCB, 0xA4, 0x89, 0x84, 0xF8, 0x35, 0xF0, 0xDF,
+ 0x45, 0x5B, 0x6A, 0xAF, 0xA8, 0x5F, 0xE4, 0xC2,
+ 0x03, 0x9B, 0x5B, 0x11, 0x21, 0xA7, 0xDE, 0xC5,
+ 0x71, 0x3D, 0x00, 0xF8, 0x6F, 0x13, 0x75, 0x4E,
+ 0x7B, 0x6B, 0x32, 0x95, 0xD3, 0x77, 0x82, 0xA2,
+ 0x70, 0x6A, 0x80, 0xC3, 0x0D, 0x53, 0xC4, 0x1C,
+ 0xF0, 0x1C, 0x5A, 0x54, 0xA4, 0xB2, 0x7A, 0x90,
+ 0x6E, 0x48, 0x39, 0x19, 0x4A, 0x70, 0x8E, 0xEB,
+ 0xF2, 0x94, 0x07, 0x45, 0xC0, 0x4B, 0xC1, 0x80,
+ 0xED, 0x87, 0x39, 0x6B, 0x5F, 0x7E, 0x63, 0x95,
+ 0x38, 0xFB, 0xF4, 0x6E, 0x3A, 0x6A, 0x78, 0x59,
+ 0x1E, 0x51, 0x45, 0x02, 0x14, 0xAC, 0xA1, 0xD1,
+ 0xC8, 0x44, 0x03, 0xB6, 0x3D, 0xA4, 0xB3, 0xC1,
+ 0xE0, 0x1C, 0x39, 0xA1, 0x87, 0x21, 0x7C, 0xBA,
+ 0x9A, 0x92, 0xA3, 0xAF, 0x37, 0xE8, 0x27, 0xA1,
+ 0xBE, 0x2D, 0x83, 0x0A, 0x46, 0xE7, 0x68, 0x44,
+ 0x9D, 0xB1, 0x57, 0x33, 0x9B, 0x57, 0xE3, 0x0C,
+ 0xE7, 0xDF, 0x7F, 0x15, 0xC0, 0xB5, 0x3A, 0x08,
+ 0x6C, 0xEF, 0xB3, 0xD3, 0xA2, 0x3C, 0x84, 0xC8,
+ 0x77, 0x46, 0xB8, 0xD0, 0x1E, 0x6D, 0x7A, 0x0B,
+ 0xD7, 0x25, 0x77, 0x74, 0xF6, 0xD8, 0xF4, 0x75,
+ 0x54, 0x6A, 0x91, 0x48, 0x98, 0xAC, 0x52, 0xA6,
+ 0x6C, 0xBC, 0x05, 0xA4, 0x92, 0x8F, 0x52, 0xAA,
+ 0x97, 0xCC, 0x23, 0xD8, 0x69, 0x01, 0xB0, 0xD2,
+ 0x1F, 0x22, 0xE8, 0xD1, 0xF7, 0x89, 0x8E, 0x40,
+ 0xF1, 0xD8, 0xCE, 0xB5, 0x26, 0x82, 0xBD, 0xD7,
+ 0x7C, 0x88, 0xB2, 0x6F, 0x16, 0x07, 0x67, 0x51,
+ 0x45, 0x6C, 0x90, 0x63, 0xBA, 0x58, 0xB6, 0x71,
+ 0xB8, 0x54, 0xA8, 0x4C, 0x54, 0xB3, 0xD7, 0x2B,
+ 0x9F, 0xEB, 0x1C, 0xC6, 0x9F, 0xFA, 0xD6, 0xD3,
+ 0xED, 0xA0, 0x99, 0x18, 0x99, 0x23, 0xB0, 0x1A,
+ 0xAA, 0x3A, 0x42, 0xCB, 0x4A, 0xFC, 0x54, 0x30,
+ 0x86, 0xD0, 0xFF, 0x44, 0x62, 0xAB, 0x94, 0xBD,
+ 0xA9, 0x95, 0x27, 0x22, 0xD6, 0x57, 0xE7, 0x26,
+ 0x94, 0x18, 0x0C, 0xDE, 0x10, 0x44, 0xE4, 0x1A,
+ 0x55, 0x15, 0x07, 0xDC, 0x33, 0xCF, 0x4D, 0x27,
+ 0x9D, 0xDD, 0x19, 0xF7, 0x81, 0xD5, 0x2A, 0xFA,
+ 0x52, 0xC5, 0xA3, 0xF9, 0x6A, 0x78, 0xE8, 0x95,
+ 0xE5, 0x00, 0x98, 0x46, 0xD0, 0xA5, 0x55, 0x23,
+ 0x0D, 0xED, 0xA3, 0x84, 0x87, 0xAF, 0xB5, 0xBC,
+ 0x10, 0x8B, 0x1F, 0x0A, 0x5E, 0x08, 0x5B, 0xC8,
+ 0x78, 0xBD, 0xBC, 0xB5, 0x29, 0x56, 0x3C, 0xFB,
+ 0x95, 0xC7, 0xFD, 0xDD, 0xB6, 0x2A, 0x66, 0x5A,
+ 0x2B, 0x86, 0xA2, 0x74, 0x33, 0x67, 0xA3, 0x48,
+ 0xE7, 0xFA, 0xCB, 0x08, 0x6B, 0x9D, 0x85, 0x8E,
+ 0x38, 0x14, 0xCB, 0xC2, 0xDA, 0xA7, 0x06, 0x3A,
+ 0x23, 0xE6, 0x80, 0x7D, 0x01, 0xA2, 0xA4, 0x1B,
+ 0x3C, 0xCF, 0x9C, 0xE8, 0x62, 0x4D, 0xF5, 0x81,
+ 0x8C, 0xB9, 0x11, 0x8A, 0x12, 0x07, 0x93, 0xDD,
+ 0xB9, 0x40, 0x32, 0xB4, 0x60, 0x6A, 0xC8, 0x76,
+ 0x95, 0x54, 0x0A, 0x48, 0xE2, 0xFF, 0x8A, 0x3C,
+ 0xA2, 0x17, 0x4A, 0xCF, 0xDF, 0x6A, 0xAF, 0xBE,
+ 0x7A, 0x62, 0x7A, 0x3A, 0x60, 0x0B, 0x64, 0x2D,
+ 0xF0, 0xF9, 0x9C, 0x0B, 0xB2, 0x1C, 0xFD, 0xB6,
+ 0x3F, 0x86, 0x9F, 0x4A, 0xA7, 0xA3, 0x8C, 0xC1,
+ 0xAD, 0xF3, 0xFA, 0x86, 0xEF, 0x3F, 0xD7, 0x86,
+ 0x05, 0xF0, 0x8D, 0xA6, 0xD1, 0xFE, 0xE0, 0xB4,
+ 0x12, 0xC6, 0x35, 0x88, 0xFE, 0x77, 0xDE, 0x4E,
+ 0x36, 0x4C, 0x8A, 0x81, 0x62, 0xC0, 0x30, 0x95,
+ 0xC9, 0x2E, 0xB5, 0xCD, 0x09, 0x8D, 0x14, 0xDF,
+ 0xED, 0x2E, 0x2D, 0xCE, 0x8A, 0x94, 0x7A, 0xC7,
+ 0x12, 0x51, 0x8B, 0xEF, 0x45, 0xE9, 0x7A, 0x5E,
+ 0x1E, 0x51, 0x73, 0x34, 0x51, 0x2B, 0xCB, 0x45,
+ 0x22, 0xE6, 0x6F, 0x62, 0x20, 0xBA, 0xD2, 0x4E,
+ 0xDC, 0x1F, 0xEE, 0x25, 0xFD, 0xA5, 0xD8, 0xD6,
+ 0x4A, 0x24, 0xEA, 0x5E, 0x36, 0xF5, 0x76, 0x76,
+ 0x27, 0x53, 0x99, 0xA1, 0xAF, 0x9E, 0x3C, 0x2A,
+ 0x4C, 0xB2, 0x26, 0x8C, 0xC4, 0x1D, 0x38, 0x0C,
+ 0x3F, 0xC6, 0x34, 0xA8, 0x5B, 0x96, 0x46, 0x4B,
+ 0xE4, 0x17, 0xB8, 0x91, 0xD8, 0x28, 0x43, 0x99,
+ 0xD8, 0xB5, 0x1D, 0x87, 0x66, 0x29, 0xC6, 0x8E,
+ 0x43, 0x07, 0xAE, 0xBC, 0x05, 0xBF, 0xE2, 0xED,
+ 0xDD, 0xCD, 0xDA, 0x65, 0xC9, 0x87, 0x95, 0xB6,
+ 0x4D, 0x64, 0x64, 0x23, 0x5D, 0x19, 0x9D, 0x47,
+ 0xC0, 0xED, 0x36, 0x03, 0x8C, 0x1E, 0xBA, 0xDE,
+ 0xB7, 0x5D, 0xB8, 0x2B, 0x10, 0x35, 0x6F, 0xCD,
+ 0x8E, 0xF8, 0xFA, 0xC0, 0x95, 0x34, 0x5C, 0x6A,
+ 0x49, 0xDB, 0x30, 0x4C, 0xEB, 0x61, 0x27, 0xF5,
+ 0x83, 0x5B, 0xBF, 0x05, 0x1F, 0x56, 0xF0, 0x4B,
+ 0x1C, 0x25, 0x29, 0xA2, 0xC5, 0xF2, 0x46, 0xF6,
+ 0xE9, 0x04, 0xDB, 0x7D, 0x01, 0xDE, 0xE0, 0x76,
+ 0xEC, 0xB0, 0x24, 0x61, 0x41, 0xA4, 0x53, 0x84,
+ 0x90, 0x1B, 0x96, 0x72, 0x00, 0x14, 0x26, 0xED,
+ 0x20, 0x31, 0x5A, 0x24, 0xC9, 0xB2, 0x2A, 0x75,
+ 0xD3, 0x94, 0xC1, 0xFE, 0xCE, 0xC1, 0x57, 0xDE,
+ 0x5E, 0xCD, 0xBE, 0xCB, 0x85, 0x4A, 0x6B, 0x85,
+ 0x28, 0xC3, 0x7B, 0x12, 0x7F, 0x61, 0xDD, 0x22,
+ 0x07, 0x37, 0xFF, 0x70, 0x7A, 0xA1, 0x56, 0xD4,
+ 0x5A, 0x3A, 0x59, 0xAB, 0xC3, 0x65, 0x09, 0x0E,
+ 0x3C, 0x9C, 0x52, 0x34, 0xB2, 0x5D, 0x89, 0x62,
+ 0x89, 0x3E, 0x22, 0x07, 0x56, 0xA2, 0x4D, 0x95,
+ 0xE8, 0x78, 0x15, 0x44, 0x6F, 0xA3, 0xB2, 0x2C,
+ 0x24, 0xF8, 0xA0, 0x54, 0x9E, 0x73, 0x25, 0x0C,
+ 0xB3, 0x2C, 0xFF, 0x2D, 0x9C, 0x2E, 0xE1, 0xD8,
+ 0x70, 0xF1, 0xCA, 0xA4, 0xB6, 0x6E, 0xDF, 0xE5,
+ 0xB4, 0x0F, 0xF7, 0x00, 0x8E, 0x4F, 0x6F, 0xBA,
+ 0x0D, 0x1F, 0x82, 0xF0, 0x7D, 0xC4, 0xED, 0x1E,
+ 0xB6, 0x61, 0xE2, 0x3C, 0xBF, 0x5F, 0x88, 0xE1,
+ 0x37, 0x5E, 0xE7, 0x7D, 0xE2, 0x13, 0xDF, 0x9A,
+ 0x59, 0x6D, 0x85, 0x87, 0x7D, 0xCD, 0x8A, 0x01,
+ 0xA1, 0xA7, 0x10, 0x63, 0xB5, 0xA4, 0xC4, 0xE0,
+ 0x1A, 0x45, 0x4E, 0x91, 0x07, 0x54, 0x62, 0xD6,
+ 0xC2, 0x3F, 0x96, 0x40, 0xF6, 0x8B, 0x12, 0x59,
+ 0xEF, 0x20, 0x9C, 0x35, 0x4E, 0x37, 0x1F, 0xAA,
+ 0x9C, 0x01, 0xA5, 0x59, 0x85, 0x37, 0x9E, 0x4F,
+ 0xDF, 0xFF, 0x40, 0x6E, 0xC2, 0xE6, 0xC6, 0x09,
+ 0x70, 0x1C, 0xC2, 0xCD, 0x11, 0x6B, 0x84, 0xC8,
+ 0xEE, 0x2B, 0xAE, 0xD5, 0x36, 0xFC, 0x83, 0x30,
+ 0xDD, 0x5E, 0x13, 0x6C, 0x49, 0xDB, 0x44, 0xDD,
+ 0x39, 0x58, 0xE7, 0x83, 0xD6, 0x1A, 0x5F, 0xE2,
+ 0xF7, 0x82, 0xDC, 0x1E, 0x80, 0x44, 0xDB, 0x48,
+ 0x62, 0x32, 0x75, 0x3E, 0x6A, 0x98, 0x1A, 0xB2,
+ 0x36, 0xBF, 0xDE, 0x35, 0x6B, 0x20, 0x9F, 0x83,
+ 0xB5, 0xA2, 0x1C, 0x0B, 0x99, 0x9B, 0x49, 0x43,
+ 0xEB, 0x5B, 0x67, 0x03, 0x8A, 0x24, 0x45, 0x8C,
+ 0x15, 0xEE, 0xD2, 0xB2, 0x35, 0xEB, 0xAF, 0x69,
+ 0x0E, 0x69, 0x3B, 0x4D, 0x80, 0x9B, 0x75, 0x43,
+ 0xB4, 0x40, 0x30, 0xCF, 0xD9, 0x76, 0xD4, 0x58,
+ 0xAC, 0x2B, 0x10, 0xE3, 0xF3, 0x48, 0x38, 0xAA,
+ 0x69, 0x18, 0x51, 0x5C, 0xD7, 0xB0, 0x9E, 0x5B,
+ 0x1E, 0x18, 0xD7, 0x59, 0x67, 0x80, 0x4F, 0xCB,
+ 0x40, 0x49, 0xB0, 0x27, 0xCD, 0x15, 0xF7, 0x56,
+ 0x34, 0x0F, 0x5D, 0xD9, 0xC4, 0xCB, 0xF7, 0x83,
+ 0x0D, 0x8B, 0xCF, 0x21, 0x13, 0x1A, 0x49, 0xE6,
+ 0x21, 0x49, 0x0F, 0x67, 0xFF, 0xE6, 0xE7, 0xF4,
+ 0xD7, 0x2C, 0xDA, 0xFD, 0xBD, 0x86, 0xC2, 0x40,
+ 0x6E, 0xB5, 0x05, 0xFC, 0x3E, 0x88, 0xB4, 0xB1,
+ 0xC1, 0x5C, 0x6D, 0x0F, 0x0F, 0x17, 0xE6, 0xE0,
+ 0x96, 0x4B, 0x45, 0xBD, 0x07, 0x20, 0x00, 0x3F,
+ 0xF0, 0xF2, 0xB9, 0xA1, 0x35, 0x01, 0x47, 0x81,
+ 0x1F, 0xA2, 0x0A, 0x66, 0xDB, 0xD7, 0x58, 0x51,
+ 0x88, 0x78, 0x24, 0x6F, 0x7E, 0x68, 0x46, 0xBD,
+ 0xEB, 0x5C, 0xA9, 0xDE, 0x30, 0x34, 0x2B, 0xA3,
+ 0xCF, 0x93, 0x82, 0x14, 0x3D, 0x96, 0x1E, 0xD7,
+ 0x6E, 0x9A, 0x2E, 0x72, 0xD0, 0x49, 0xDB, 0x24,
+ 0xA0, 0x6E, 0x8E, 0xBA, 0x4A, 0x36, 0xCB, 0xF6,
+ 0x9A, 0x46, 0x24, 0xEF, 0x18, 0xA8, 0xD9, 0xD5,
+ 0x93, 0xF0, 0x2B, 0xEC, 0x60, 0x0A, 0x8F, 0x1C,
+ 0xE8, 0x69, 0x56, 0x14, 0x6C, 0x8E, 0x30, 0xFB,
+ 0x8D, 0xCF, 0xE7, 0x92, 0x59, 0x2E, 0x32, 0xEB,
+ 0xAE, 0xA3, 0x99, 0x87, 0x98, 0x49, 0x03, 0xCD,
+ 0x5E, 0xBD, 0xDE, 0xB9, 0xF5, 0xD0, 0xB3, 0xB1,
+ 0x65, 0xAC, 0xC7, 0x42, 0xB4, 0xCF, 0x6A, 0x00,
+ 0x3E, 0x2E, 0xC1, 0x13, 0xDF, 0x5E, 0x2E, 0xEC,
+ 0x30, 0x00, 0xE2, 0xAB, 0xFD, 0x74, 0x06, 0x55,
+ 0x88, 0x07, 0xB0, 0xEF, 0x6D, 0x43, 0x81, 0x15,
+ 0xFC, 0xF6, 0x96, 0x91, 0x3D, 0x2F, 0xFE, 0xBD,
+ 0xB9, 0xC8, 0xB6, 0x81, 0x63, 0xE0, 0xA9, 0x20,
+ 0x93, 0xEC, 0x4B, 0x1E, 0xB9, 0xC2, 0xD0, 0x8C,
+ 0x2E, 0xCB, 0x18, 0x7D, 0x1F, 0x66, 0xA6, 0x96,
+ 0xA9, 0xB8, 0x66, 0x4F, 0xCF, 0xC9, 0xDA, 0x97,
+ 0xCA, 0x07, 0xF1, 0xC8, 0xFB, 0x56, 0x60, 0xA9,
+ 0x25, 0xDB, 0xFC, 0x2D, 0xB6, 0x0A, 0x42, 0x6A,
+ 0x7F, 0xCE, 0x70, 0x91, 0xFF, 0x3B, 0xAC, 0xAB,
+ 0xF2, 0x23, 0x4E, 0x50, 0xE9, 0xE6, 0x2F, 0xCB,
+ 0x98, 0xBA, 0x7D, 0xD2, 0x8A, 0xDE, 0x6E, 0x80,
+ 0x0C, 0xC6, 0xEB, 0xD9, 0x64, 0xD4, 0x59, 0xD5,
+ 0x75, 0x00, 0x18, 0x7F, 0xD6, 0x86, 0xC2, 0x25,
+ 0x98, 0xA9, 0x28, 0x1C, 0x40, 0x46, 0xC6, 0xA5,
+ 0xAF, 0x6E, 0x5D, 0x25, 0x3C, 0x77, 0xF9, 0x43,
+ 0xF3, 0x20, 0xFC, 0x43, 0xA0, 0x5E, 0xF1, 0x65,
+ 0x5D, 0x8B, 0x33, 0x5A, 0x94, 0xF0, 0x6F, 0xB6,
+ 0xD4, 0x4A, 0x48, 0x64, 0x31, 0x73, 0x17, 0x4E,
+ 0x88, 0x90, 0xA8, 0xE4, 0x7F, 0xCE, 0xD5, 0x7D,
+ 0xE3, 0x84, 0x3F, 0x38, 0x71, 0x4C, 0xB1, 0x18,
+ 0xAA, 0x46, 0xF2, 0xCF, 0x99, 0xF0, 0x24, 0xD7,
+ 0xFD, 0xFC, 0x2C, 0x81, 0x25, 0xC1, 0x8E, 0x0B,
+ 0x82, 0x4C, 0x14, 0x6C, 0x44, 0xB1, 0x78, 0x67,
+ 0x14, 0x47, 0xCA, 0x70, 0x0D, 0x13, 0xD1, 0xA8,
+ 0x73, 0xBC, 0x4E, 0xAA, 0x1E, 0xB7, 0x59, 0xC0,
+ 0xAC, 0xE3, 0x21, 0x2B, 0x55, 0x22, 0x6A, 0x53,
+ 0xA6, 0xF0, 0xE9, 0x56, 0x37, 0x3B, 0xD6, 0x1B,
+ 0x2E, 0x57, 0x98, 0x4D, 0x6A, 0x7E, 0xEB, 0x2E,
+ 0x9B, 0xB8, 0xE2, 0x27, 0x55, 0xE2, 0x2E, 0xFA,
+ 0x3C, 0xD2, 0x7A, 0xCC, 0xDB, 0x5C, 0x45, 0x85,
+ 0xA6, 0x92, 0x49, 0x79, 0x9D, 0x18, 0x20, 0x50,
+ 0x7B, 0xF4, 0x0F, 0x43, 0x2F, 0x7B, 0x3E, 0x90,
+ 0xEF, 0xF3, 0x29, 0x66, 0xDF, 0xD1, 0xE9, 0x44,
+ 0xC6, 0x28, 0xAA, 0x48, 0x00, 0x5F, 0x12, 0xEB,
+ 0xEC, 0x26, 0x7F, 0xB3, 0x83, 0xFB, 0x50, 0x5A,
+ 0x5F, 0x5A, 0x8E, 0x08, 0x4B, 0xF7, 0x50, 0x10,
+ 0xC8, 0x73, 0x8F, 0x9C, 0xF6, 0xCB, 0xDC, 0xEA,
+ 0x78, 0x07, 0x2C, 0x59, 0xAD, 0x66, 0x48, 0xFF,
+ 0x56, 0x7D, 0x99, 0xC9, 0xEA, 0x64, 0xE7, 0xD0,
+ 0x46, 0x88, 0x58, 0x46, 0x93, 0x37, 0x70, 0xC1,
+ 0x91, 0x40, 0x02, 0x46, 0x7F, 0x8D, 0xFE, 0x66,
+ 0x07, 0x1F, 0x3B, 0x56, 0x6A, 0x6E, 0x88, 0xB2,
+ 0xBB, 0xC0, 0xC8, 0xCD, 0xD9, 0xDC, 0x0A, 0x0C,
+ 0x1A, 0x27, 0x35, 0x48, 0x4C, 0x5B, 0x5D, 0x90,
+ 0xA0, 0xB2, 0xB4, 0xCE, 0xD6, 0xDD, 0x07, 0x13,
+ 0x7C, 0x93, 0x99, 0xA2, 0xA9, 0xAC, 0xC3, 0xC8,
+ 0xEF, 0x1D, 0x33, 0x3D, 0x3F, 0x42, 0x52, 0x57,
+ 0x6D, 0x72, 0x87, 0x8E, 0x96, 0xA8, 0xC6, 0xC8,
+ 0xD0, 0xD6, 0xE8, 0xEB, 0xF2, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0E, 0x1E, 0x29, 0x3D,
+};
+
+uint8_t mldsa_44_message[] = {
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x6D, 0x65, 0x73, 0x73,
+ 0x61, 0x67, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x62,
+ 0x65, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64,
+ 0x2E, 0x0A,
+};
+
+uint8_t mldsa_44_privkey_noseed[] = {
+ 0xBA, 0x71, 0xF9, 0xF6, 0x4E, 0x11, 0xBA, 0xEB,
+ 0x58, 0xFA, 0x9C, 0x6F, 0xBB, 0x6E, 0x14, 0xE6,
+ 0x1F, 0x18, 0x64, 0x3D, 0xAB, 0x49, 0x5B, 0x47,
+ 0x53, 0x9A, 0x91, 0x66, 0xCA, 0x01, 0x98, 0x13,
+ 0xC5, 0xC1, 0x61, 0x0A, 0x40, 0x77, 0x4F, 0x0E,
+ 0xBA, 0x33, 0x34, 0xF8, 0xB5, 0xBE, 0x56, 0xE8,
+ 0x78, 0x71, 0xB3, 0xC3, 0xA7, 0x72, 0xC0, 0x72,
+ 0x0F, 0xA3, 0x76, 0x66, 0xAE, 0x17, 0x35, 0xFD,
+ 0xE6, 0xBC, 0x38, 0xA1, 0xC3, 0x5F, 0x8C, 0xF0,
+ 0x8E, 0x44, 0x09, 0x24, 0xC9, 0x03, 0x71, 0x97,
+ 0xBB, 0x87, 0xFD, 0xC4, 0x64, 0x6B, 0x86, 0xDA,
+ 0x5A, 0x05, 0x89, 0xA3, 0x26, 0xCC, 0x0C, 0x0D,
+ 0x95, 0x0F, 0xF8, 0xB5, 0xA9, 0xEA, 0x41, 0x35,
+ 0xEA, 0xB8, 0xA9, 0x3F, 0x80, 0xF0, 0x92, 0x7E,
+ 0x12, 0x40, 0x46, 0xE2, 0x5B, 0x23, 0x66, 0xAE,
+ 0xA2, 0x5A, 0x6D, 0x1D, 0x0F, 0xEF, 0x98, 0x21,
+ 0x04, 0xB8, 0x09, 0xDA, 0x12, 0x48, 0xE1, 0x40,
+ 0x4C, 0x11, 0x03, 0x85, 0x99, 0xB0, 0x4D, 0x61,
+ 0x04, 0x0A, 0xC0, 0x34, 0x28, 0x23, 0x16, 0x80,
+ 0x08, 0x12, 0x45, 0x11, 0x49, 0x0C, 0xA0, 0x96,
+ 0x0D, 0xC2, 0xA8, 0x01, 0x5A, 0xA8, 0x65, 0x0B,
+ 0x30, 0x25, 0xD4, 0x94, 0x44, 0x8B, 0x38, 0x8C,
+ 0x10, 0x24, 0x41, 0x22, 0x40, 0x69, 0x8A, 0x04,
+ 0x04, 0x0C, 0x26, 0x90, 0xE3, 0x34, 0x69, 0xE2,
+ 0x24, 0x68, 0xD2, 0x44, 0x00, 0x0B, 0x84, 0x90,
+ 0xD9, 0x42, 0x30, 0x21, 0x91, 0x8D, 0x09, 0x99,
+ 0x64, 0x20, 0x39, 0x60, 0x82, 0x36, 0x21, 0x90,
+ 0xB8, 0x4C, 0x02, 0x12, 0x6E, 0x24, 0xB9, 0x70,
+ 0x84, 0x22, 0x01, 0xE1, 0xA8, 0x64, 0x44, 0x26,
+ 0x0E, 0x01, 0x17, 0x0E, 0x82, 0x40, 0x6C, 0x9B,
+ 0x38, 0x6D, 0x0A, 0x93, 0x50, 0x52, 0x22, 0x25,
+ 0xD2, 0xB8, 0x2C, 0x1A, 0x25, 0x70, 0x90, 0x12,
+ 0x22, 0xD1, 0xB2, 0x80, 0x22, 0x46, 0x52, 0x01,
+ 0x34, 0x80, 0x40, 0x34, 0x21, 0x41, 0x06, 0x60,
+ 0x41, 0x32, 0x82, 0x09, 0x45, 0x90, 0x52, 0x32,
+ 0x29, 0x83, 0xB8, 0x44, 0x93, 0x12, 0x21, 0x0A,
+ 0xC1, 0x89, 0x60, 0xB2, 0x71, 0x9C, 0x90, 0x69,
+ 0x90, 0x82, 0x90, 0x89, 0x12, 0x49, 0x40, 0x40,
+ 0x8A, 0x5C, 0x10, 0x48, 0x01, 0x87, 0x91, 0x03,
+ 0xB0, 0x40, 0xD8, 0x44, 0x05, 0xE4, 0xB0, 0x29,
+ 0x0A, 0x27, 0x90, 0x1C, 0xC9, 0x50, 0x58, 0x02,
+ 0x8C, 0x0C, 0x49, 0x72, 0x49, 0x84, 0x6D, 0x19,
+ 0xA7, 0x85, 0xE3, 0x00, 0x30, 0xCB, 0xB2, 0x21,
+ 0xE2, 0x08, 0x10, 0x4C, 0xA6, 0x64, 0x11, 0x43,
+ 0x68, 0x52, 0x94, 0x69, 0x09, 0x39, 0x32, 0x91,
+ 0xA2, 0x6D, 0xCA, 0x14, 0x84, 0xA3, 0x92, 0x11,
+ 0xDB, 0x94, 0x2C, 0x01, 0xC6, 0x64, 0x14, 0x24,
+ 0x8C, 0x1A, 0x15, 0x31, 0x0A, 0x23, 0x0E, 0xD8,
+ 0x14, 0x20, 0xA4, 0x26, 0x8D, 0x43, 0x40, 0x90,
+ 0xC1, 0x42, 0x86, 0xA4, 0x10, 0x85, 0x0C, 0x32,
+ 0x2D, 0xD0, 0x28, 0x60, 0x1B, 0xB5, 0x0C, 0x52,
+ 0x44, 0x61, 0x21, 0x15, 0x24, 0x21, 0xC6, 0x04,
+ 0xD8, 0x34, 0x31, 0xD9, 0x12, 0x71, 0xA2, 0x34,
+ 0x52, 0x03, 0x30, 0x89, 0x54, 0x32, 0x10, 0x83,
+ 0x94, 0x08, 0xA2, 0xA4, 0x70, 0xD2, 0x44, 0x8E,
+ 0x84, 0x02, 0x8D, 0x91, 0x46, 0x62, 0x0B, 0x00,
+ 0x0E, 0xA0, 0x80, 0x70, 0x22, 0xB5, 0x0D, 0x0B,
+ 0xC9, 0x01, 0x00, 0x26, 0x4D, 0xE2, 0x44, 0x80,
+ 0x93, 0x20, 0x65, 0xC9, 0x96, 0x8D, 0xDA, 0xA4,
+ 0x4C, 0x42, 0xA8, 0x00, 0x1A, 0x27, 0x6C, 0xC3,
+ 0x94, 0x4D, 0xA0, 0x30, 0x2C, 0xDA, 0xA8, 0x04,
+ 0x23, 0xA3, 0x8C, 0x63, 0x04, 0x0E, 0x59, 0xC8,
+ 0x00, 0x20, 0xA9, 0x6C, 0xC4, 0x06, 0x50, 0x82,
+ 0x00, 0x2E, 0x5C, 0xB2, 0x44, 0x61, 0x46, 0x51,
+ 0x0C, 0x18, 0x80, 0x18, 0x38, 0x82, 0x02, 0x25,
+ 0x90, 0xA2, 0xB2, 0x60, 0x21, 0xA0, 0x40, 0x20,
+ 0x49, 0x2A, 0x52, 0x28, 0x86, 0x93, 0xA6, 0x28,
+ 0x9B, 0x94, 0x71, 0x02, 0xB9, 0x6D, 0x49, 0xA0,
+ 0x2C, 0x09, 0x25, 0x28, 0x18, 0x93, 0x09, 0x10,
+ 0x49, 0x4C, 0x13, 0xC9, 0x91, 0xA3, 0x88, 0x2D,
+ 0x50, 0x12, 0x31, 0x63, 0xB4, 0x00, 0xA4, 0x00,
+ 0x4E, 0x04, 0xB6, 0x68, 0x12, 0x14, 0x26, 0x00,
+ 0x17, 0x00, 0x9B, 0x92, 0x0C, 0x51, 0xA8, 0x65,
+ 0x11, 0x44, 0x8D, 0x44, 0x42, 0x69, 0x00, 0xA5,
+ 0x6D, 0x04, 0xA9, 0x69, 0x43, 0x94, 0x69, 0x4C,
+ 0xB8, 0x60, 0x52, 0x26, 0x2D, 0xA1, 0x32, 0x11,
+ 0xCA, 0xB0, 0x11, 0x1B, 0x81, 0x90, 0x12, 0x11,
+ 0x64, 0x42, 0x86, 0x89, 0x9C, 0x12, 0x51, 0xDC,
+ 0xC0, 0x41, 0x13, 0x47, 0x68, 0x9B, 0x20, 0x92,
+ 0xD1, 0x26, 0x91, 0x23, 0x96, 0x50, 0x13, 0xB3,
+ 0x4C, 0x12, 0x45, 0x69, 0x21, 0xA1, 0x05, 0x0C,
+ 0x46, 0x65, 0x99, 0x38, 0x30, 0x99, 0x26, 0x2E,
+ 0x19, 0x15, 0x72, 0x11, 0x39, 0x8D, 0x89, 0x10,
+ 0x92, 0x50, 0x28, 0x11, 0x48, 0xA6, 0x49, 0x52,
+ 0xB6, 0x2D, 0xC9, 0x30, 0x4D, 0xD9, 0x32, 0x91,
+ 0x91, 0xA6, 0x44, 0x14, 0x34, 0x0E, 0x13, 0x39,
+ 0x41, 0x98, 0x06, 0x0C, 0x22, 0x25, 0x6C, 0x14,
+ 0x47, 0x70, 0x21, 0xB7, 0x60, 0x23, 0x98, 0x25,
+ 0xE4, 0x24, 0x6E, 0xD1, 0xB6, 0x44, 0x51, 0x44,
+ 0x2C, 0x41, 0x42, 0x85, 0xE0, 0x44, 0x42, 0x89,
+ 0x42, 0x42, 0xC2, 0x24, 0x2C, 0xCC, 0xC6, 0x68,
+ 0x13, 0x12, 0x69, 0x98, 0x30, 0x49, 0x23, 0x28,
+ 0x6A, 0x14, 0xC8, 0x11, 0x60, 0x92, 0x30, 0x11,
+ 0x26, 0x52, 0x92, 0xB0, 0x00, 0x5C, 0x84, 0x2C,
+ 0x4A, 0x14, 0x29, 0x0A, 0x95, 0x40, 0xE3, 0xC4,
+ 0x05, 0x0C, 0xC8, 0x89, 0xA1, 0x26, 0x62, 0x44,
+ 0x10, 0x04, 0x9A, 0xC8, 0x70, 0x0C, 0x93, 0x60,
+ 0x90, 0xB6, 0x30, 0x12, 0x17, 0x71, 0x23, 0x18,
+ 0x4E, 0xD4, 0x10, 0x85, 0x84, 0x20, 0x82, 0x5C,
+ 0x14, 0x48, 0x90, 0xB2, 0x51, 0xA0, 0x18, 0x92,
+ 0x93, 0x94, 0x80, 0x1A, 0x49, 0x72, 0xC0, 0x02,
+ 0x06, 0xE1, 0xA6, 0x8C, 0xA1, 0x80, 0x4D, 0x4A,
+ 0x26, 0x08, 0x18, 0x07, 0x62, 0x42, 0x12, 0x40,
+ 0x10, 0x41, 0x64, 0x44, 0x42, 0x4E, 0x94, 0x86,
+ 0x40, 0x9A, 0x84, 0x41, 0x21, 0xC5, 0x71, 0x01,
+ 0x96, 0x29, 0x19, 0x40, 0x4E, 0x94, 0x36, 0x22,
+ 0x24, 0xC3, 0x20, 0x22, 0x88, 0x71, 0x84, 0x20,
+ 0x4C, 0x64, 0x20, 0x69, 0xDB, 0x84, 0x24, 0x24,
+ 0x25, 0x46, 0x21, 0xC4, 0x71, 0x8A, 0x14, 0x64,
+ 0x01, 0x20, 0x65, 0x4C, 0x84, 0x24, 0x44, 0x24,
+ 0x30, 0x8A, 0x22, 0x70, 0xD3, 0x86, 0x30, 0x0B,
+ 0xB4, 0x6C, 0x21, 0x23, 0x0A, 0x8B, 0xB8, 0x4D,
+ 0x5C, 0xF7, 0xD7, 0xE6, 0x89, 0x30, 0x2B, 0xED,
+ 0xB1, 0xC5, 0x86, 0x7E, 0x7D, 0x26, 0x9B, 0x1C,
+ 0xDB, 0x07, 0xF8, 0x25, 0x64, 0x10, 0x82, 0xE1,
+ 0x9A, 0x8D, 0xA2, 0xF9, 0x30, 0x77, 0xE8, 0xB1,
+ 0xFC, 0x3D, 0x4E, 0x6B, 0x2D, 0x32, 0x58, 0x33,
+ 0x6B, 0x4F, 0x9C, 0x64, 0x55, 0x15, 0x3A, 0xC0,
+ 0x40, 0xA8, 0x47, 0xFB, 0x64, 0x7F, 0xBB, 0x6B,
+ 0x55, 0x2A, 0x40, 0x00, 0x71, 0xFE, 0x17, 0x72,
+ 0x48, 0x5B, 0x7A, 0x9D, 0x1F, 0x0D, 0x14, 0x7B,
+ 0xF3, 0x38, 0x8C, 0x56, 0x54, 0x71, 0xE4, 0xE6,
+ 0x2C, 0xC3, 0xCE, 0x0D, 0x0C, 0x0F, 0xC3, 0x60,
+ 0xDF, 0x92, 0x89, 0xED, 0x99, 0x18, 0x37, 0x6B,
+ 0x8B, 0x8B, 0x93, 0x14, 0x50, 0x47, 0xF8, 0xFE,
+ 0xA2, 0x98, 0x60, 0x07, 0xC2, 0xAA, 0x89, 0x92,
+ 0x2F, 0x69, 0xEB, 0x47, 0x5B, 0x59, 0x7B, 0x2B,
+ 0xBA, 0x23, 0x7B, 0x9C, 0x84, 0x2E, 0x3F, 0xF1,
+ 0xD3, 0x25, 0xE8, 0x2A, 0x1F, 0x23, 0xE9, 0x49,
+ 0x89, 0xD0, 0x06, 0xBC, 0x7C, 0xE4, 0x94, 0x6F,
+ 0x2E, 0x8B, 0x77, 0xE1, 0x08, 0x48, 0x46, 0x3C,
+ 0x47, 0xFE, 0x7B, 0x20, 0x9E, 0x2A, 0x61, 0x7D,
+ 0xDD, 0x41, 0x79, 0x6A, 0xE6, 0x14, 0x5E, 0x70,
+ 0x9C, 0xDA, 0x94, 0x06, 0xF2, 0x26, 0x12, 0x57,
+ 0xC2, 0x13, 0xB4, 0xB3, 0x0D, 0xA3, 0x0A, 0xC2,
+ 0x5B, 0x0D, 0x06, 0xCF, 0x79, 0xA8, 0x12, 0xC5,
+ 0xFC, 0xB0, 0xEF, 0x11, 0xD9, 0xFE, 0xDF, 0xE0,
+ 0x99, 0x4A, 0xFE, 0x3B, 0x69, 0xB0, 0x6A, 0x29,
+ 0x16, 0xCF, 0x69, 0x2B, 0x9D, 0xA7, 0x60, 0x28,
+ 0xE5, 0xF3, 0xA0, 0x48, 0x79, 0xE6, 0x96, 0xD2,
+ 0x1F, 0x73, 0x5C, 0x37, 0x83, 0x15, 0x36, 0x4D,
+ 0xB0, 0xA4, 0xE0, 0xAB, 0x6B, 0x53, 0xD3, 0x1E,
+ 0xFA, 0xF3, 0x0D, 0x65, 0xE3, 0x7A, 0x1B, 0x6A,
+ 0x77, 0x04, 0x6F, 0x04, 0xC6, 0x4B, 0xA1, 0x07,
+ 0x2A, 0x97, 0x80, 0xE0, 0xC5, 0x66, 0xC9, 0x43,
+ 0x39, 0xA4, 0xD1, 0x9D, 0x00, 0x68, 0xC5, 0x7D,
+ 0x6E, 0x6F, 0x0B, 0x51, 0x2D, 0xB7, 0x13, 0x4A,
+ 0x95, 0x0E, 0xAF, 0x4F, 0x7B, 0x01, 0xA5, 0xFD,
+ 0xD0, 0x65, 0xB9, 0x1B, 0xFA, 0x29, 0xE4, 0x42,
+ 0x36, 0x79, 0xCD, 0xE7, 0x4B, 0xC6, 0xA8, 0xF1,
+ 0xC8, 0x4C, 0x4D, 0xF7, 0x83, 0x87, 0x23, 0x1D,
+ 0xC8, 0x5C, 0xE3, 0x26, 0x70, 0x44, 0x59, 0x03,
+ 0xC4, 0xBE, 0xBE, 0xE3, 0xF5, 0x0C, 0x43, 0xE5,
+ 0x04, 0x49, 0x49, 0x69, 0x11, 0xAA, 0x93, 0xE7,
+ 0xE3, 0x95, 0x78, 0x74, 0x14, 0xD3, 0x17, 0x68,
+ 0xD9, 0x91, 0x25, 0x20, 0xF8, 0x3C, 0x02, 0xFF,
+ 0x01, 0x12, 0x4D, 0xCF, 0x0E, 0x12, 0x5F, 0xAF,
+ 0xD5, 0xB9, 0xD7, 0xE7, 0xDD, 0xA4, 0xF5, 0xB5,
+ 0x0C, 0x70, 0xAE, 0xBB, 0x85, 0x99, 0xA2, 0xE4,
+ 0x47, 0x6A, 0x0D, 0xE5, 0x31, 0xB0, 0x40, 0x26,
+ 0x72, 0xDF, 0x75, 0x75, 0x14, 0x2D, 0x86, 0x01,
+ 0x60, 0x5C, 0x94, 0x01, 0x79, 0x23, 0xF6, 0x4A,
+ 0xC5, 0x77, 0xC4, 0xBE, 0xD8, 0xD8, 0xE8, 0x9A,
+ 0x74, 0xCA, 0x9F, 0x38, 0x19, 0xCB, 0xF1, 0x42,
+ 0xA7, 0x2D, 0xEB, 0xE7, 0x7C, 0x4E, 0xFB, 0x71,
+ 0x27, 0xE2, 0xD8, 0xC1, 0xB7, 0xBF, 0xB6, 0x42,
+ 0x86, 0xC0, 0xBD, 0x52, 0x23, 0x3F, 0x43, 0xC6,
+ 0x7D, 0x57, 0x17, 0xF9, 0x7A, 0xD8, 0x28, 0x54,
+ 0x87, 0x3D, 0xDC, 0x7F, 0x71, 0xD6, 0x56, 0xAA,
+ 0xA6, 0xEF, 0x70, 0x70, 0x60, 0xAF, 0x28, 0x0B,
+ 0x9F, 0x45, 0x4B, 0x4F, 0xED, 0xB4, 0x77, 0x6E,
+ 0x83, 0xB2, 0xFD, 0xBA, 0x20, 0xA4, 0x5A, 0xEF,
+ 0xEB, 0x54, 0x9A, 0x1E, 0xD0, 0x38, 0x20, 0x21,
+ 0x89, 0x3C, 0xA9, 0xA6, 0xE7, 0x4C, 0xCC, 0x30,
+ 0xA2, 0x55, 0x39, 0x37, 0xCC, 0xEF, 0x34, 0x38,
+ 0x99, 0xB5, 0x02, 0xCF, 0x46, 0xDD, 0xB8, 0xDD,
+ 0x1D, 0x95, 0xFE, 0xFB, 0x60, 0xC9, 0xB2, 0x04,
+ 0x69, 0xA1, 0x50, 0x3B, 0x2A, 0x68, 0x75, 0x87,
+ 0x83, 0x0D, 0x33, 0xCE, 0xE9, 0xA7, 0x2D, 0x79,
+ 0x8F, 0xCF, 0x4A, 0x9B, 0x45, 0x2C, 0x85, 0x49,
+ 0xF5, 0x59, 0xC5, 0xD9, 0xFC, 0x6B, 0xFE, 0x08,
+ 0x3F, 0x44, 0x6C, 0x2D, 0x90, 0x39, 0x81, 0xD9,
+ 0xF2, 0x64, 0x92, 0x48, 0x3A, 0xB4, 0x52, 0xEA,
+ 0x5B, 0xB1, 0x00, 0x8F, 0xFE, 0xAC, 0x97, 0x5D,
+ 0xA0, 0x27, 0x59, 0x59, 0x3E, 0x7E, 0x06, 0x63,
+ 0x61, 0x07, 0x3A, 0x83, 0xB2, 0x7B, 0x53, 0x1A,
+ 0x3D, 0x0D, 0xDA, 0x51, 0x7C, 0xA9, 0x90, 0xEA,
+ 0x32, 0x35, 0xD1, 0xD7, 0xB5, 0xE0, 0x9D, 0xA5,
+ 0xF0, 0x2D, 0xC1, 0x52, 0x5B, 0x1D, 0xA6, 0x85,
+ 0x96, 0x5B, 0x54, 0xFC, 0x2A, 0x3A, 0x73, 0xA1,
+ 0x79, 0x0E, 0x0E, 0xFB, 0x69, 0xE7, 0x0A, 0x78,
+ 0xFA, 0x55, 0x03, 0x44, 0xEA, 0x8C, 0x75, 0x3D,
+ 0xBF, 0x18, 0x63, 0x9B, 0xAA, 0x8C, 0xB1, 0x25,
+ 0x9A, 0xA7, 0x4F, 0x68, 0xF9, 0x2A, 0xBA, 0x80,
+ 0x07, 0xC6, 0x18, 0xCC, 0xB6, 0xF5, 0x06, 0x9F,
+ 0xF4, 0x6B, 0x97, 0x51, 0xBB, 0xFF, 0xF3, 0x7D,
+ 0xF3, 0x21, 0x36, 0x0F, 0x0F, 0x5C, 0x0E, 0x7F,
+ 0x56, 0x26, 0xDD, 0x12, 0x9A, 0xE3, 0xAE, 0x2A,
+ 0x7C, 0x56, 0xCD, 0xB6, 0x11, 0xED, 0xA4, 0xC9,
+ 0x8F, 0xEC, 0x83, 0x16, 0x3C, 0xD5, 0x11, 0x68,
+ 0x78, 0xC1, 0xA9, 0x3E, 0xBA, 0xA2, 0x6D, 0xB4,
+ 0x05, 0xEA, 0xF4, 0xA7, 0xAB, 0xA2, 0x77, 0x83,
+ 0x7D, 0xE9, 0xA5, 0x15, 0x04, 0x70, 0x76, 0x24,
+ 0xEF, 0x2E, 0x1B, 0xBB, 0xCA, 0x29, 0x24, 0x11,
+ 0x16, 0x7F, 0x2E, 0x3D, 0x39, 0x0C, 0x0E, 0x51,
+ 0xF8, 0x4A, 0x2F, 0x13, 0x83, 0x90, 0xE3, 0x3F,
+ 0x85, 0x83, 0x5D, 0x38, 0xA9, 0x4D, 0xBB, 0xE7,
+ 0x1E, 0x6C, 0x82, 0x1E, 0x86, 0xB1, 0x1F, 0xFD,
+ 0x89, 0xEF, 0xF4, 0xBF, 0xE2, 0x08, 0xD6, 0x00,
+ 0x5D, 0x28, 0xF7, 0x04, 0xBA, 0xEA, 0xD1, 0xF2,
+ 0x5D, 0xE0, 0xEB, 0x24, 0x1B, 0x18, 0xFC, 0x7F,
+ 0xA0, 0xDD, 0xD9, 0x0D, 0xC1, 0x39, 0xBE, 0x7F,
+ 0xCB, 0xEB, 0x97, 0x30, 0xFA, 0xE4, 0xB5, 0xD1,
+ 0x72, 0x70, 0xCE, 0x4C, 0x67, 0x0C, 0x42, 0x57,
+ 0x0A, 0x9C, 0xF2, 0x5B, 0xC4, 0xFA, 0xE5, 0xCD,
+ 0x31, 0xE5, 0xD5, 0x5A, 0xD0, 0x22, 0x6A, 0x94,
+ 0xBE, 0x52, 0x94, 0x8C, 0x67, 0x02, 0xA9, 0x86,
+ 0xA0, 0xAD, 0xBF, 0xCD, 0x3A, 0xC4, 0x82, 0xBB,
+ 0x12, 0xAB, 0xBB, 0x79, 0xA2, 0xF6, 0x60, 0x28,
+ 0x42, 0x15, 0x3B, 0x2F, 0x82, 0xA3, 0xB3, 0xCD,
+ 0x16, 0x88, 0xE7, 0x4D, 0x36, 0x53, 0x4B, 0xFF,
+ 0x8C, 0x48, 0xD3, 0xC4, 0x51, 0xEB, 0x2C, 0x5F,
+ 0x98, 0xFE, 0xB9, 0xE7, 0x86, 0x4D, 0x60, 0xAF,
+ 0x96, 0xE8, 0x3B, 0x21, 0x62, 0x46, 0x74, 0x82,
+ 0xF0, 0x58, 0x63, 0x9C, 0x86, 0xA7, 0x85, 0xA9,
+ 0xA1, 0xD4, 0xB6, 0x9B, 0xC3, 0x0E, 0x77, 0xA6,
+ 0x4C, 0x3B, 0xBC, 0xD7, 0xDE, 0xB4, 0xE3, 0xD3,
+ 0x0F, 0x1A, 0x67, 0x21, 0x20, 0x3D, 0x87, 0xA8,
+ 0x8A, 0xB8, 0x5E, 0x02, 0x7A, 0x97, 0x42, 0xFC,
+ 0x68, 0x8F, 0x0A, 0xDF, 0x15, 0x72, 0x8E, 0x59,
+ 0x7E, 0x91, 0x0C, 0xFE, 0x5D, 0xF3, 0x3C, 0x56,
+ 0xA1, 0x36, 0xEF, 0x39, 0xC7, 0xCA, 0x5D, 0x65,
+ 0x0C, 0x2B, 0x9F, 0x90, 0x1C, 0x9B, 0x89, 0xE1,
+ 0xE0, 0x93, 0x54, 0x93, 0x61, 0xF3, 0x03, 0xBE,
+ 0x88, 0x39, 0xD1, 0x45, 0x4C, 0xCE, 0xB5, 0xFB,
+ 0xC4, 0x43, 0x5F, 0xA0, 0xDA, 0xB5, 0x8A, 0x8F,
+ 0xC2, 0x85, 0x36, 0x0E, 0xEA, 0x49, 0x1C, 0xA0,
+ 0x77, 0x96, 0x1C, 0x4A, 0xAA, 0x3E, 0x96, 0xDE,
+ 0x99, 0x71, 0xB9, 0x4F, 0xDF, 0xA5, 0x20, 0x7C,
+ 0xCF, 0x0D, 0x9D, 0xAB, 0x2C, 0x48, 0x96, 0xF0,
+ 0x7E, 0xB6, 0x77, 0x1A, 0x38, 0x3C, 0x65, 0x12,
+ 0xF4, 0x1E, 0xA2, 0x8D, 0xEE, 0xE4, 0x07, 0xFD,
+ 0xAE, 0x3C, 0x57, 0x4F, 0x5D, 0x41, 0x6A, 0x89,
+ 0x7A, 0x27, 0xEF, 0x7C, 0xF5, 0x96, 0xF0, 0x43,
+ 0x2D, 0x62, 0x4A, 0x2C, 0x4E, 0xAC, 0xE5, 0x2F,
+ 0x3C, 0xBF, 0x2C, 0x63, 0x31, 0xB8, 0x0C, 0x9C,
+ 0x91, 0x65, 0xBF, 0x13, 0x34, 0x24, 0x69, 0x32,
+ 0x02, 0x4E, 0xC0, 0xBE, 0x44, 0xB3, 0x21, 0x36,
+ 0xB4, 0xE4, 0x34, 0x27, 0x91, 0x35, 0x85, 0x03,
+ 0x64, 0xC7, 0x57, 0xF1, 0xDC, 0xFA, 0x63, 0x85,
+ 0xE2, 0x56, 0x33, 0x12, 0xC5, 0xF5, 0x53, 0xF0,
+ 0xC8, 0x44, 0xEA, 0xBB, 0x79, 0x11, 0xCE, 0xE7,
+ 0x60, 0xCA, 0xEB, 0x3E, 0x19, 0x3B, 0xF3, 0xA9,
+ 0xC3, 0x81, 0x14, 0x87, 0x23, 0x9A, 0xD2, 0xE0,
+ 0x14, 0x78, 0xF4, 0x6E, 0x41, 0x8A, 0x5D, 0xE5,
+ 0x6B, 0x7F, 0x17, 0x55, 0xBA, 0x68, 0xF9, 0xA3,
+ 0x74, 0x61, 0x3B, 0x5D, 0xE2, 0xED, 0x26, 0xC5,
+ 0x80, 0xC7, 0x72, 0xDB, 0xDB, 0xFA, 0xB1, 0xF7,
+ 0xE3, 0xF5, 0x7D, 0x94, 0xF8, 0x4E, 0x30, 0xDE,
+ 0xB2, 0x9D, 0x70, 0xA9, 0x1D, 0xF2, 0x88, 0xFC,
+ 0x43, 0xA2, 0x76, 0xDF, 0xED, 0x58, 0xE2, 0xB0,
+ 0xDB, 0x53, 0x83, 0xE5, 0x32, 0xB6, 0xEE, 0xDF,
+ 0xB3, 0x92, 0xE4, 0x3D, 0xC3, 0xDA, 0x72, 0x01,
+ 0xA0, 0x68, 0xF5, 0x23, 0x1E, 0xE5, 0x22, 0x09,
+ 0x8D, 0x68, 0x59, 0xB2, 0xD5, 0x64, 0x63, 0xA8,
+ 0x91, 0x7B, 0x3C, 0x25, 0x61, 0x65, 0x79, 0x66,
+ 0xDB, 0xC4, 0x78, 0x56, 0xB6, 0xFF, 0xC8, 0x2B,
+ 0xCC, 0x37, 0x9F, 0xFD, 0x08, 0xB2, 0x59, 0xF3,
+ 0xD9, 0xD7, 0x87, 0x3B, 0xA8, 0xFC, 0xBE, 0x4C,
+ 0x94, 0x13, 0xB6, 0x01, 0x15, 0x91, 0x60, 0x70,
+ 0x1D, 0xF0, 0x04, 0x70, 0xB1, 0x49, 0xBD, 0xF3,
+ 0x2F, 0x4D, 0x3C, 0xFC, 0xFB, 0x9D, 0xEB, 0xC7,
+ 0x72, 0x41, 0x71, 0x7D, 0x13, 0x06, 0x7A, 0xAE,
+ 0xD2, 0x3C, 0x7A, 0x26, 0x51, 0x18, 0x51, 0x69,
+ 0xF1, 0x26, 0x70, 0x61, 0xFB, 0x6B, 0x30, 0xE4,
+ 0xFE, 0xA7, 0x3F, 0x66, 0xF4, 0xF9, 0x27, 0x56,
+ 0xAC, 0x26, 0x23, 0x41, 0x8A, 0xF8, 0xB2, 0xA3,
+ 0x98, 0x71, 0x1B, 0x7C, 0x68, 0x07, 0xB4, 0x34,
+ 0x25, 0xE1, 0xD9, 0x9B, 0xFD, 0xCD, 0x5D, 0xF5,
+ 0x31, 0x95, 0x28, 0x79, 0x06, 0xA3, 0x32, 0xF5,
+ 0x99, 0x71, 0xA0, 0xC3, 0x43, 0x97, 0x5F, 0xC3,
+ 0x20, 0xAD, 0x13, 0x7C, 0x9E, 0x34, 0xCE, 0x7C,
+ 0xE8, 0x55, 0x20, 0xB2, 0x6C, 0xA1, 0x97, 0xA1,
+ 0xFA, 0x2D, 0xF2, 0xEC, 0xD4, 0xE3, 0xFA, 0x83,
+ 0x3B, 0x3B, 0xD2, 0xC2, 0x44, 0x82, 0x80, 0x42,
+ 0x52, 0xCF, 0x1D, 0xF6, 0xAD, 0xC6, 0x39, 0x8F,
+ 0x35, 0xE9, 0x8A, 0xB1, 0x87, 0x10, 0x40, 0x76,
+ 0x80, 0xC9, 0xC1, 0xDB, 0xAC, 0x8C, 0x7E, 0xDC,
+ 0x86, 0x46, 0xB9, 0x70, 0x82, 0xE2, 0xE1, 0x21,
+ 0xFA, 0xA7, 0xFA, 0xC2, 0x1E, 0x4A, 0x33, 0x83,
+ 0x84, 0xCB, 0x92, 0x20, 0x2C, 0x61, 0xBD, 0x12,
+ 0x6C, 0x5D, 0xDD, 0x45, 0x8B, 0x32, 0x7A, 0x18,
+ 0xBD, 0x71, 0x6F, 0x14, 0x2C, 0xA5, 0xCD, 0xB3,
+ 0xE4, 0x9D, 0x7E, 0xB8, 0xD9, 0x62, 0xB5, 0xB8,
+ 0x5A, 0x88, 0xF7, 0x99, 0xB6, 0x9A, 0x6A, 0x66,
+ 0xC7, 0xBD, 0x62, 0x9F, 0x56, 0xB4, 0x3C, 0x02,
+ 0x90, 0x62, 0x9B, 0x5E, 0x27, 0x4C, 0xDE, 0xC7,
+ 0xA0, 0x72, 0x29, 0xE7, 0x93, 0x9A, 0x77, 0xD3,
+ 0x2E, 0x8E, 0xF7, 0x30, 0xFC, 0xCE, 0xAD, 0x9C,
+ 0x4E, 0x06, 0x77, 0xA8, 0x3A, 0x03, 0x30, 0xAB,
+ 0x76, 0x5D, 0x33, 0x6D, 0xD2, 0xAA, 0x15, 0x5D,
+ 0xCD, 0x2A, 0xC7, 0xF3, 0x15, 0x29, 0x77, 0x4F,
+ 0x49, 0x36, 0xB0, 0x5D, 0x0B, 0x14, 0xB4, 0x8F,
+ 0xAA, 0x1E, 0x8C, 0xD4, 0x50, 0x56, 0xE5, 0x6C,
+ 0x13, 0x9B, 0x17, 0xF8, 0x90, 0x71, 0x5A, 0xD6,
+ 0x3D, 0x6C, 0x4A, 0x9F, 0x2D, 0x97, 0x6C, 0x8B,
+ 0x63, 0x5B, 0xDF, 0xE5, 0x86, 0x02, 0x81, 0x6F,
+ 0x61, 0x2C, 0x6E, 0x4B, 0x22, 0x53, 0x67, 0xCB,
+ 0x9A, 0x7B, 0xB7, 0x9C, 0x01, 0x8F, 0x1B, 0x8C,
+ 0x53, 0x15, 0x18, 0x0A, 0xAD, 0xBE, 0x3A, 0xB7,
+ 0x5A, 0xC3, 0x56, 0x20, 0x6F, 0xE2, 0x7C, 0x12,
+ 0xDF, 0x3B, 0x56, 0x97, 0x84, 0xE3, 0xA5, 0x38,
+ 0xFB, 0x05, 0x24, 0x18, 0x26, 0x6E, 0x72, 0xDB,
+ 0x40, 0x0D, 0x6F, 0x32, 0xC4, 0x29, 0x7F, 0x34,
+ 0xF9, 0xF1, 0xAF, 0x18, 0x6C, 0x37, 0x65, 0x65,
+ 0x5F, 0x11, 0xB3, 0xE5, 0xA3, 0xC8, 0x04, 0x9B,
+ 0x7D, 0xF1, 0x40, 0x11, 0xFF, 0x21, 0x5F, 0xBF,
+ 0x17, 0xBF, 0x89, 0xEE, 0x97, 0x6C, 0xF0, 0xDB,
+ 0xAB, 0x62, 0x70, 0x10, 0x4E, 0x7E, 0x31, 0x9D,
+ 0x1F, 0x64, 0xC5, 0x9E, 0x20, 0x9E, 0x35, 0x82,
+};
+
+uint8_t mldsa_44_pubkey_noseed[] = {
+ 0xBA, 0x71, 0xF9, 0xF6, 0x4E, 0x11, 0xBA, 0xEB,
+ 0x58, 0xFA, 0x9C, 0x6F, 0xBB, 0x6E, 0x14, 0xE6,
+ 0x1F, 0x18, 0x64, 0x3D, 0xAB, 0x49, 0x5B, 0x47,
+ 0x53, 0x9A, 0x91, 0x66, 0xCA, 0x01, 0x98, 0x13,
+ 0x1C, 0x44, 0xF8, 0x26, 0xBB, 0xD5, 0x6E, 0x34,
+ 0xE5, 0x5D, 0xB5, 0xE5, 0xE2, 0xD7, 0x33, 0x48,
+ 0x5E, 0x39, 0xEA, 0x26, 0x0F, 0xC6, 0x00, 0x0C,
+ 0x5E, 0xA4, 0xBA, 0x80, 0xD3, 0x45, 0x5C, 0xDE,
+ 0x53, 0xB4, 0x6F, 0x34, 0x48, 0x2A, 0xED, 0xFD,
+ 0x54, 0x50, 0xFC, 0x2E, 0x1B, 0xA4, 0xF2, 0x5D,
+ 0x15, 0xF9, 0xC1, 0x44, 0x24, 0x2F, 0xB3, 0x9B,
+ 0xB5, 0x22, 0x87, 0x18, 0x90, 0x30, 0xC5, 0x04,
+ 0x98, 0xE1, 0x71, 0x7B, 0x7C, 0x75, 0x8B, 0x19,
+ 0x0A, 0x67, 0x48, 0xEA, 0x9A, 0xA3, 0xF7, 0xAC,
+ 0xAA, 0xF2, 0xC7, 0xCB, 0x52, 0x6E, 0xD7, 0x17,
+ 0xC9, 0xF7, 0x9A, 0xEB, 0x84, 0x21, 0x4F, 0xA5,
+ 0xCD, 0x8D, 0xED, 0x92, 0xA0, 0xC3, 0xFA, 0x15,
+ 0x58, 0x81, 0x0F, 0x12, 0xC7, 0x05, 0x0A, 0x36,
+ 0x77, 0x08, 0xD1, 0x96, 0xCD, 0x24, 0xE5, 0xAF,
+ 0x97, 0x49, 0x04, 0xAE, 0xD8, 0xE4, 0xCE, 0x88,
+ 0x72, 0xE8, 0x69, 0x6B, 0x0B, 0x7B, 0xCA, 0x50,
+ 0xE4, 0x52, 0xCD, 0x7D, 0x30, 0xEA, 0x9A, 0x4A,
+ 0xDA, 0xC0, 0x31, 0x1D, 0x67, 0x2C, 0x6B, 0xDE,
+ 0x84, 0x96, 0x24, 0x0B, 0x07, 0x43, 0x14, 0x63,
+ 0x70, 0x88, 0x95, 0xCD, 0x9B, 0xAF, 0xC3, 0x16,
+ 0x32, 0xD7, 0x39, 0x76, 0x49, 0x38, 0x8F, 0xDA,
+ 0xFC, 0xBF, 0x7D, 0x30, 0x5A, 0x3D, 0xE9, 0xA4,
+ 0x95, 0xEC, 0xA7, 0x43, 0x3A, 0x8F, 0x83, 0xBA,
+ 0x0F, 0x0B, 0x25, 0xC4, 0x13, 0xC6, 0xE3, 0x9C,
+ 0x96, 0xEB, 0x7D, 0x69, 0x1B, 0x34, 0xD3, 0x7C,
+ 0xE3, 0x7F, 0x1E, 0xEA, 0xD1, 0xCF, 0x21, 0x7E,
+ 0x25, 0xEF, 0x34, 0xEE, 0xCF, 0x3F, 0x7C, 0x60,
+ 0xF8, 0x4B, 0x8E, 0xDF, 0xDD, 0xE8, 0x40, 0x5D,
+ 0x4F, 0x83, 0x25, 0x76, 0xC6, 0x1E, 0xF9, 0x8E,
+ 0x0A, 0x2F, 0x28, 0xDA, 0x18, 0x77, 0x00, 0x95,
+ 0x39, 0x24, 0xF6, 0x86, 0xB9, 0x46, 0x14, 0x70,
+ 0x5B, 0xCF, 0x53, 0xD3, 0x3F, 0xED, 0xD4, 0x34,
+ 0x8E, 0xDD, 0xDB, 0xDF, 0x28, 0xB5, 0x06, 0x5E,
+ 0x1F, 0x20, 0x77, 0x50, 0x43, 0xE8, 0x5C, 0xF9,
+ 0x31, 0xF8, 0x29, 0x17, 0x93, 0x63, 0xA1, 0xA7,
+ 0xE7, 0x40, 0x4A, 0x83, 0x8E, 0xC0, 0x00, 0x86,
+ 0xB0, 0x97, 0x63, 0x86, 0xFE, 0x63, 0x7C, 0x98,
+ 0x24, 0x47, 0x57, 0xE3, 0xF7, 0x69, 0xDD, 0xD4,
+ 0x46, 0x74, 0x71, 0xBF, 0xAD, 0x67, 0x0F, 0x9A,
+ 0x05, 0xF8, 0x24, 0x6E, 0xE5, 0x0A, 0x7B, 0x1E,
+ 0xAF, 0x87, 0xFC, 0x40, 0x69, 0xC3, 0xAE, 0x2A,
+ 0xA2, 0x03, 0x32, 0x58, 0x11, 0x77, 0x92, 0xF0,
+ 0xBC, 0xD4, 0x9E, 0x08, 0x3F, 0xD1, 0xBC, 0x74,
+ 0x96, 0xAB, 0xFF, 0x29, 0xCC, 0x94, 0xE4, 0x86,
+ 0x8B, 0x21, 0x21, 0x4E, 0xD3, 0x16, 0x52, 0x53,
+ 0x99, 0xA6, 0x10, 0xFB, 0xDD, 0x4A, 0x80, 0xE7,
+ 0xC8, 0x07, 0x15, 0xF2, 0x95, 0x78, 0xE2, 0xA8,
+ 0x4B, 0xB4, 0x0B, 0xDD, 0xDB, 0xD9, 0xF4, 0x7A,
+ 0x11, 0xB6, 0xE7, 0xDA, 0x11, 0x8A, 0x1B, 0x65,
+ 0x8D, 0x35, 0x9E, 0x8A, 0xEF, 0x55, 0xEB, 0x46,
+ 0xB5, 0x37, 0x6B, 0x5B, 0x65, 0x59, 0x79, 0x98,
+ 0x4A, 0x92, 0x2B, 0xEE, 0xBF, 0xC5, 0x9B, 0xCD,
+ 0x60, 0x0D, 0x53, 0x09, 0xDC, 0xCD, 0x72, 0xDB,
+ 0xF0, 0x78, 0x7D, 0xB8, 0xBA, 0x75, 0x7B, 0x53,
+ 0x7C, 0x1E, 0xAF, 0xD5, 0xC0, 0xF5, 0x0E, 0xA4,
+ 0xBC, 0x95, 0x83, 0x54, 0x9E, 0x28, 0x29, 0xA4,
+ 0x2C, 0x28, 0xCA, 0xC2, 0x48, 0xC9, 0x6D, 0x78,
+ 0x12, 0x4C, 0x47, 0x15, 0x9B, 0x18, 0xAE, 0xDD,
+ 0x75, 0x4A, 0xBA, 0x17, 0xB1, 0x9D, 0x43, 0x0F,
+ 0xB7, 0x8F, 0x63, 0x3E, 0xA9, 0xD2, 0x6F, 0x54,
+ 0xA9, 0xBD, 0x50, 0xF8, 0xD8, 0xF6, 0xB7, 0x35,
+ 0x94, 0xF8, 0x28, 0x97, 0x6E, 0x7E, 0xA0, 0x9C,
+ 0x53, 0xBB, 0xB9, 0xF1, 0x1A, 0x56, 0xC9, 0x50,
+ 0x7F, 0xB8, 0x9B, 0x9A, 0x5E, 0xBC, 0x03, 0x7A,
+ 0x37, 0x26, 0x7A, 0x95, 0xF8, 0x5B, 0x8D, 0x64,
+ 0xCA, 0x97, 0x19, 0x2B, 0x10, 0xA6, 0x6F, 0x41,
+ 0x7B, 0x3F, 0x61, 0xFE, 0x9C, 0xA5, 0x71, 0x30,
+ 0xA4, 0x8F, 0xD9, 0x25, 0xEA, 0xE2, 0xAB, 0x55,
+ 0x02, 0xD5, 0x71, 0xC8, 0xA5, 0x19, 0x03, 0xC1,
+ 0xD3, 0x98, 0xF4, 0xC1, 0xF7, 0x6A, 0x7E, 0x11,
+ 0x74, 0x39, 0x76, 0xAF, 0xDB, 0xC6, 0x97, 0xF2,
+ 0x30, 0x94, 0xA3, 0xCD, 0x76, 0x1F, 0xF9, 0x68,
+ 0x5D, 0xE3, 0x2E, 0x09, 0xFB, 0x3C, 0x28, 0xAD,
+ 0xD4, 0x53, 0x49, 0x03, 0x00, 0xBC, 0x7C, 0x89,
+ 0xDC, 0x01, 0x78, 0x00, 0x96, 0x07, 0x17, 0x22,
+ 0x94, 0x57, 0x75, 0xF2, 0x64, 0xE1, 0xB0, 0x62,
+ 0x3B, 0xCF, 0x46, 0x19, 0xC7, 0x12, 0xC8, 0x38,
+ 0x76, 0x12, 0x05, 0xD8, 0x76, 0x91, 0xB7, 0x5E,
+ 0xF3, 0x60, 0x19, 0x6C, 0xBB, 0x9E, 0x9B, 0x92,
+ 0xA0, 0xD4, 0xC4, 0xED, 0x62, 0x32, 0x6E, 0x50,
+ 0x24, 0xD7, 0x75, 0x10, 0xB8, 0xEE, 0x2C, 0x74,
+ 0x26, 0xCC, 0x22, 0xEA, 0xE2, 0x09, 0xDC, 0x9F,
+ 0x13, 0xBD, 0xE6, 0xBF, 0x08, 0xF5, 0xE7, 0x18,
+ 0x1B, 0xD3, 0xB4, 0x59, 0x45, 0x0B, 0x45, 0x1A,
+ 0x51, 0x53, 0x9A, 0x71, 0x5C, 0x21, 0xD6, 0x7D,
+ 0xD3, 0x30, 0xEB, 0x59, 0x70, 0xDB, 0x00, 0xD9,
+ 0xED, 0xBF, 0xB2, 0x82, 0x2B, 0x03, 0x6F, 0xA1,
+ 0x3B, 0xAF, 0xEB, 0x86, 0xD8, 0xDC, 0x78, 0x86,
+ 0x6E, 0x3F, 0x8D, 0x43, 0xE5, 0x3D, 0x78, 0xCC,
+ 0xA5, 0x59, 0x5A, 0x6F, 0xAF, 0x88, 0x6B, 0x5D,
+ 0xC1, 0x12, 0xF1, 0xCF, 0x4A, 0xDC, 0xFA, 0x87,
+ 0x58, 0x00, 0xD9, 0x0B, 0x48, 0x88, 0x3A, 0xF9,
+ 0x73, 0x16, 0xFE, 0x15, 0x06, 0x87, 0x3F, 0xC1,
+ 0x57, 0xE5, 0x70, 0xEA, 0xCB, 0xFD, 0x22, 0x28,
+ 0x68, 0xD1, 0x42, 0x34, 0x10, 0x19, 0x66, 0xAF,
+ 0xB6, 0xBF, 0x99, 0x40, 0x82, 0x92, 0x53, 0xA9,
+ 0x53, 0xAD, 0xA8, 0x9F, 0xC7, 0x56, 0xB6, 0xA8,
+ 0x49, 0xF7, 0x0A, 0xCB, 0x98, 0x38, 0xE6, 0x9F,
+ 0xAA, 0x50, 0xBB, 0xA7, 0x5E, 0x3E, 0x89, 0xC2,
+ 0xAD, 0xB5, 0x7E, 0x86, 0xD0, 0x88, 0xAB, 0x9B,
+ 0x04, 0xA2, 0x8E, 0x67, 0x07, 0x09, 0x17, 0x22,
+ 0x43, 0xEC, 0x5E, 0x00, 0x08, 0xA5, 0xCE, 0xAF,
+ 0x3F, 0x87, 0x22, 0xF4, 0x87, 0x30, 0x25, 0x96,
+ 0xFF, 0xD7, 0x55, 0xAD, 0x1B, 0x82, 0xA4, 0x9C,
+ 0x34, 0xB3, 0x46, 0x95, 0x15, 0xB4, 0x6A, 0xA2,
+ 0x90, 0xCD, 0x86, 0xEE, 0x38, 0xEA, 0x7A, 0x9B,
+ 0xE3, 0xF1, 0x03, 0x61, 0x03, 0x35, 0xB5, 0x31,
+ 0xCC, 0xA3, 0x33, 0xDD, 0xFE, 0x32, 0xB1, 0x45,
+ 0x10, 0xF4, 0xB0, 0x7E, 0xF9, 0x5F, 0xC6, 0x68,
+ 0x4E, 0x8C, 0x45, 0x4A, 0x92, 0xC1, 0x0D, 0xBB,
+ 0x5D, 0x59, 0xC7, 0xA7, 0xC6, 0x3F, 0xB3, 0x05,
+ 0xFE, 0x88, 0x19, 0x67, 0xD9, 0x9E, 0x66, 0x9E,
+ 0xB6, 0x32, 0x84, 0x05, 0x82, 0x56, 0x0B, 0xB4,
+ 0x03, 0x43, 0x1D, 0x40, 0xF7, 0x5A, 0x49, 0x54,
+ 0x90, 0x84, 0x82, 0x27, 0x82, 0x92, 0x82, 0x1F,
+ 0x4E, 0xA9, 0x1E, 0x42, 0xE7, 0x8F, 0xA4, 0x8C,
+ 0xAE, 0xE3, 0xC8, 0x36, 0x14, 0x6D, 0xCF, 0xD7,
+ 0x38, 0xD1, 0x17, 0xE9, 0x2E, 0x9A, 0x15, 0x13,
+ 0x7D, 0x28, 0xE8, 0xE6, 0xA4, 0xB4, 0x62, 0x26,
+ 0x50, 0xCB, 0x41, 0x35, 0x04, 0xCB, 0x3A, 0x33,
+ 0x5D, 0x44, 0xBE, 0xEC, 0x57, 0x46, 0xC1, 0xC2,
+ 0x94, 0xB1, 0xE8, 0xCB, 0x99, 0xCB, 0x60, 0x8D,
+ 0x92, 0x8F, 0x8C, 0xE3, 0x56, 0x36, 0x32, 0xC5,
+ 0x21, 0xF2, 0x3D, 0x13, 0xC6, 0x1A, 0x8F, 0x61,
+ 0xC0, 0x1D, 0xF8, 0xC9, 0x6C, 0x73, 0x60, 0xDB,
+ 0x4F, 0x3C, 0x68, 0xAA, 0x5D, 0x2F, 0xDD, 0x34,
+ 0x2A, 0x62, 0xFF, 0x34, 0x59, 0xC1, 0x16, 0x38,
+ 0x94, 0x21, 0xAB, 0x43, 0xE8, 0x58, 0x4C, 0x45,
+ 0x88, 0x2B, 0x50, 0xE6, 0xE4, 0xE9, 0x6D, 0xB6,
+ 0xF0, 0xB8, 0xFD, 0xE8, 0x90, 0xD5, 0xDB, 0xFA,
+ 0xDC, 0xD8, 0x86, 0x90, 0xB4, 0x49, 0xE6, 0x42,
+ 0x40, 0xDD, 0xB2, 0x02, 0x37, 0x47, 0xF3, 0x08,
+ 0x36, 0x3E, 0x30, 0x1A, 0xA7, 0x77, 0x57, 0x16,
+ 0x9F, 0xC6, 0x15, 0x06, 0x28, 0xD5, 0x92, 0x0B,
+ 0x5A, 0xA1, 0xAB, 0x1C, 0x8C, 0xBF, 0x44, 0xCB,
+ 0x00, 0xE0, 0x25, 0xD7, 0x87, 0x9D, 0x72, 0xB4,
+ 0x79, 0xE3, 0xAF, 0x53, 0x11, 0xC7, 0x85, 0x72,
+ 0x55, 0x90, 0xDA, 0x9C, 0x89, 0xB9, 0xFC, 0x3B,
+ 0x84, 0x50, 0x76, 0x95, 0x54, 0xEB, 0x44, 0xD2,
+ 0x03, 0xEB, 0xA2, 0xBB, 0xAE, 0xF9, 0xCA, 0xD2,
+ 0x23, 0x70, 0x11, 0xC2, 0xEA, 0x44, 0xEF, 0xF0,
+ 0x0F, 0x29, 0x9A, 0x48, 0xFF, 0xE2, 0x8C, 0xA9,
+ 0x3D, 0xDF, 0x85, 0xF7, 0x66, 0x08, 0x24, 0x2E,
+ 0xF8, 0xD6, 0xCC, 0x24, 0x61, 0x0A, 0x1E, 0x20,
+ 0x78, 0xFC, 0xAC, 0x4F, 0x93, 0x85, 0xC3, 0x14,
+ 0x90, 0x5E, 0xCA, 0xA8, 0x2E, 0x55, 0x39, 0x16,
+ 0xD9, 0x4D, 0x1A, 0x7C, 0x1E, 0xC6, 0x52, 0xAA,
+ 0x08, 0x89, 0x70, 0x83, 0xDA, 0xA2, 0xEB, 0xB1,
+ 0x77, 0x5F, 0xBC, 0x47, 0x1A, 0xE2, 0x77, 0x77,
+ 0xD7, 0x90, 0x4E, 0xA9, 0xF1, 0xB9, 0x2B, 0xCA,
+ 0xC3, 0xD8, 0xA3, 0x15, 0x84, 0x26, 0x08, 0x7B,
+ 0x64, 0x5B, 0x11, 0x08, 0xF0, 0xD6, 0x5F, 0xEC,
+ 0x93, 0x78, 0x9C, 0x05, 0x37, 0x43, 0xCA, 0x14,
+ 0xFD, 0x63, 0xD0, 0x5E, 0x98, 0xB6, 0x52, 0xDF,
+ 0x2B, 0x9C, 0x2F, 0xF9, 0xCE, 0x05, 0xF1, 0x94,
+ 0x07, 0x03, 0xFF, 0xB2, 0x73, 0xF8, 0x0E, 0x0E,
+ 0x27, 0x32, 0xEC, 0xA9, 0x96, 0x0D, 0x98, 0x1B,
+ 0x4C, 0xFD, 0x3B, 0x7B, 0xB8, 0x04, 0x5B, 0x3C,
+ 0x38, 0x30, 0x54, 0x6B, 0x9D, 0xD8, 0xDB, 0x0D,
+};
+
+uint8_t mldsa_44_extmu[] = {
+ 0x1B, 0x2A, 0xA5, 0xD5, 0xE3, 0xF3, 0xC1, 0xD4,
+ 0x8D, 0x7C, 0xE6, 0x8F, 0xE9, 0xE3, 0xD1, 0xF5,
+ 0x2E, 0x4B, 0x7C, 0xD6, 0x2A, 0xF4, 0x2E, 0xE5,
+ 0x8F, 0xC3, 0xB1, 0xA4, 0xB9, 0xD1, 0x2C, 0x8B,
+ 0x9E, 0x4D, 0x7A, 0xA9, 0x7C, 0xD3, 0xE6, 0x5A,
+ 0xF4, 0x1B, 0x2A, 0xA5, 0xD5, 0xE3, 0xF3, 0xC1,
+ 0xD4, 0x8D, 0x7C, 0xE6, 0x8F, 0xE9, 0xE3, 0xD1,
+ 0xF5, 0x2E, 0x4B, 0x7C, 0xD6, 0x2A, 0xF4, 0x2E,
+};
+
struct
cperf_rsa_test_data rsa_qt_perf_data[4] = {
{
@@ -4292,6 +5910,49 @@ struct cperf_mlkem_test_data mlkem_decap_perf_data[] = {
}
};
+struct cperf_mldsa_test_data mldsa_sign_perf_data[] = {
+ {
+ .name = "mldsa_44_sign (deterministic)",
+ .type = RTE_CRYPTO_ML_DSA_44,
+ .privkey = {
+ .data = mldsa_44_privkey_noseed,
+ .length = sizeof(mldsa_44_privkey_noseed),
+ },
+ .pubkey = {
+ .data = mldsa_44_pubkey_noseed,
+ .length = sizeof(mldsa_44_pubkey_noseed),
+ },
+ .message = {
+ .data = mldsa_44_message,
+ .length = sizeof(mldsa_44_message),
+ },
+ .sign = {
+ .data = mldsa_44_sign_dtrm,
+ .length = sizeof(mldsa_44_sign_dtrm),
+ },
+ .sign_deterministic = true,
+ },
+};
+
+struct cperf_mldsa_test_data mldsa_verify_perf_data[] = {
+ {
+ .name = "mldsa_44_verify",
+ .type = RTE_CRYPTO_ML_DSA_44,
+ .pubkey = {
+ .data = mldsa_44_pubkey_noseed,
+ .length = sizeof(mldsa_44_pubkey_noseed),
+ },
+ .message = {
+ .data = mldsa_44_message,
+ .length = sizeof(mldsa_44_message),
+ },
+ .sign = {
+ .data = mldsa_44_sign_dtrm,
+ .length = sizeof(mldsa_44_sign_dtrm),
+ },
+ },
+};
+
struct cperf_test_vector*
cperf_test_vector_get_dummy(struct cperf_options *options)
{
diff --git a/app/test-crypto-perf/cperf_test_vectors.h b/app/test-crypto-perf/cperf_test_vectors.h
index e498196ae3..6b4b4f22b4 100644
--- a/app/test-crypto-perf/cperf_test_vectors.h
+++ b/app/test-crypto-perf/cperf_test_vectors.h
@@ -188,6 +188,41 @@ struct cperf_sm2_test_data {
int curve;
};
+struct cperf_mldsa_test_data {
+ const char *name;
+ enum rte_crypto_ml_dsa_type type;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } privkey;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } pubkey;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } message;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } sign;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } ctx;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } seed;
+ struct {
+ uint8_t *data;
+ uint32_t length;
+ } mu;
+ enum rte_crypto_auth_algorithm hash;
+ bool sign_deterministic;
+};
+
struct cperf_test_vector*
cperf_test_vector_get_dummy(struct cperf_options *options);
@@ -215,5 +250,7 @@ extern struct cperf_rsa_test_data rsa_qt_perf_data[4];
extern struct cperf_rsa_plaintext rsa_plaintext;
extern struct cperf_mlkem_test_data mlkem_encap_perf_data[];
extern struct cperf_mlkem_test_data mlkem_decap_perf_data[];
+extern struct cperf_mldsa_test_data mldsa_sign_perf_data[];
+extern struct cperf_mldsa_test_data mldsa_verify_perf_data[];
#endif
diff --git a/app/test-crypto-perf/main.c b/app/test-crypto-perf/main.c
index 2e228201ab..c4d844d225 100644
--- a/app/test-crypto-perf/main.c
+++ b/app/test-crypto-perf/main.c
@@ -55,6 +55,7 @@ const char *cperf_op_type_strs[] = {
[CPERF_ASYM_SM2] = "sm2",
[CPERF_TLS] = "tls-record",
[CPERF_ASYM_MLKEM512] = "mlkem_512",
+ [CPERF_ASYM_MLDSA44] = "mldsa_44",
};
const char *cperf_rsa_priv_keytype_strs[] = {
@@ -247,6 +248,7 @@ cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
case CPERF_ASYM_SM2:
case CPERF_ASYM_RSA:
case CPERF_ASYM_MLKEM512:
+ case CPERF_ASYM_MLDSA44:
case CPERF_ASYM_MODEX:
conf.ff_disable |= (RTE_CRYPTODEV_FF_SECURITY |
RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO);
@@ -516,6 +518,21 @@ cperf_verify_devices_capabilities(struct cperf_options *opts,
opts->sm2_data->sign_s.length = sm2_perf_data.sign_s.length;
}
}
+ if (opts->op_type == CPERF_ASYM_MLDSA44) {
+ asym_cap_idx.type = RTE_CRYPTO_ASYM_XFORM_ML_DSA;
+ asym_capability = rte_cryptodev_asym_capability_get(cdev_id, &asym_cap_idx);
+ if (asym_capability == NULL)
+ return -1;
+
+ if (opts->asym_op_type == RTE_CRYPTO_ASYM_OP_SIGN)
+ opts->mldsa_data = &mldsa_sign_perf_data[0];
+ else if (opts->asym_op_type == RTE_CRYPTO_ASYM_OP_VERIFY)
+ opts->mldsa_data = &mldsa_verify_perf_data[0];
+ else {
+ RTE_LOG(ERR, USER1, "Unsupported MLDSA operation type\n");
+ return -ENOTSUP;
+ }
+ }
if (opts->op_type == CPERF_ASYM_MLKEM512) {
asym_cap_idx.type = RTE_CRYPTO_ASYM_XFORM_ML_KEM;
diff --git a/doc/guides/tools/cryptoperf.rst b/doc/guides/tools/cryptoperf.rst
index 13f9db66f4..7a7ee5c884 100644
--- a/doc/guides/tools/cryptoperf.rst
+++ b/doc/guides/tools/cryptoperf.rst
@@ -184,6 +184,7 @@ The following are the application command-line options:
rsa
sm2
mlkem_512
+ mldsa_44
ipsec
tls-record
--
2.43.0
^ permalink raw reply related
* [PATCH v2] net/mlx5: fix counter TAILQ race between free and query callback
From: Linhu Li @ 2026-06-08 13:25 UTC (permalink / raw)
To: dev; +Cc: stable, dsosnowski, Linhu Li
In-Reply-To: <20260604101112.72177-1-lilinhu618@gmail.com>
flow_dv_counter_free() inserts counters into
pool->counters[pool->query_gen] under pool->csl. Meanwhile,
mlx5_flow_async_pool_query_handle() moves counters from
pool->counters[query_gen ^ 1] to the global free list via
TAILQ_CONCAT while holding only cmng->csl, not pool->csl.
The comment in flow_dv_counter_free() claims the lock is not needed
because the query callback and the release function operate on
different lists. That holds only if the free path always observes
the up-to-date query_gen. It can be violated:
1. A counter free thread (non-PMD, e.g. OVS offload thread) reads
pool->query_gen == 0 and is about to insert into counters[0].
2. The free thread is preempted by the OS scheduler; it is a regular
pthread, not pinned to a core.
3. The eal-intr-thread alarm fires: query_gen++ (now 1) and the async
query is sent.
4. Hardware completes the query and the callback runs TAILQ_CONCAT on
counters[0] (= query_gen ^ 1).
5. The free thread resumes and runs TAILQ_INSERT_TAIL on counters[0]
concurrently with step 4 on another core.
Because the two paths take different locks, TAILQ_INSERT_TAIL and
TAILQ_CONCAT run concurrently on the same list with no
synchronization and corrupt it: the pool-local list ends up with a
NULL head but a dangling tqh_last, and the global free list tail no
longer points to the real tail. The just-freed counter and every
counter inserted afterwards become unreachable and are leaked.
Non-PMD threads can be preempted for hundreds of microseconds under
CPU pressure, which is well within the async query round-trip time,
so the window is reachable in practice.
Fix it by taking pool->csl in the query completion callback before
operating on pool->counters[query_gen], serializing the CONCAT with
any concurrent INSERT. The lock is taken once per pool per query
completion in the eal-intr-thread context, not on the datapath, so
the cost is negligible. Lock order is pool->csl then cmng->csl,
matching all other sites.
Also handle the error path: previously the counters accumulated in
pool->counters[query_gen] were abandoned when a query failed. Move
them back to the global free list to avoid a leak on persistent
query failures.
Fixes: ac79183dc6f7 ("net/mlx5: optimize free counter lookup")
Cc: stable@dpdk.org
Signed-off-by: Linhu Li <lilinhu618@gmail.com>
---
drivers/net/mlx5/mlx5_flow.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 915ea29a5a..20aad87f5d 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -9904,6 +9904,20 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
if (unlikely(status)) {
raw_to_free = pool->raw_hw;
+ /*
+ * The query failed, so the freed counters accumulated in the
+ * old-gen list during this round would otherwise be stranded.
+ * Move them back to the global free list to avoid a leak when
+ * queries fail persistently.
+ */
+ if (!TAILQ_EMPTY(&pool->counters[query_gen])) {
+ rte_spinlock_lock(&pool->csl);
+ rte_spinlock_lock(&cmng->csl[cnt_type]);
+ TAILQ_CONCAT(&cmng->counters[cnt_type],
+ &pool->counters[query_gen], next);
+ rte_spinlock_unlock(&cmng->csl[cnt_type]);
+ rte_spinlock_unlock(&pool->csl);
+ }
} else {
raw_to_free = pool->raw;
if (pool->is_aged)
@@ -9913,11 +9927,20 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh,
rte_spinlock_unlock(&pool->sl);
/* Be sure the new raw counters data is updated in memory. */
rte_io_wmb();
+ /*
+ * A counter free thread may have read a stale query_gen
+ * before the generation was flipped and could still be
+ * inserting into this same old-gen list. Hold pool->csl to
+ * serialize TAILQ_CONCAT with that TAILQ_INSERT_TAIL and
+ * avoid corrupting the list.
+ */
if (!TAILQ_EMPTY(&pool->counters[query_gen])) {
+ rte_spinlock_lock(&pool->csl);
rte_spinlock_lock(&cmng->csl[cnt_type]);
TAILQ_CONCAT(&cmng->counters[cnt_type],
&pool->counters[query_gen], next);
rte_spinlock_unlock(&cmng->csl[cnt_type]);
+ rte_spinlock_unlock(&pool->csl);
}
}
LIST_INSERT_HEAD(&sh->sws_cmng.free_stat_raws, raw_to_free, next);
--
2.39.3 (Apple Git-146)
^ permalink raw reply related
* RE: [PATCH v4] ethdev: support inline calculating masked item value
From: Bing Zhao @ 2026-06-09 5:23 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Slava Ovsiienko, dev@dpdk.org, Raslan Darawsheh, Ori Kam,
Dariusz Sosnowski, Suanming Mou, Matan Azrad,
NBU-Contact-Thomas Monjalon (EXTERNAL)
In-Reply-To: <20260608084558.4dd4c07c@phoenix.local>
Hi,
Let me check and update with v5.
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Monday, June 8, 2026 11:46 PM
> To: Bing Zhao <bingz@nvidia.com>
> Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; dev@dpdk.org; Raslan
> Darawsheh <rasland@nvidia.com>; Ori Kam <orika@nvidia.com>; Dariusz
> Sosnowski <dsosnowski@nvidia.com>; Suanming Mou <suanmingm@nvidia.com>;
> Matan Azrad <matan@nvidia.com>; NBU-Contact-Thomas Monjalon (EXTERNAL)
> <thomas@monjalon.net>
> Subject: Re: [PATCH v4] ethdev: support inline calculating masked item
> value
>
> External email: Use caution opening links or attachments
>
>
> On Wed, 3 Jun 2026 12:28:05 +0300
> Bing Zhao <bingz@nvidia.com> wrote:
>
> > In the asynchronous API definition and some drivers, the rte_flow_item
> > spec value may not be calculated by the driver due to the reason of
> > speed of light rule insertion rate and sometimes the input parameters
> > will be copied and changed internally.
> >
> > After copying, the spec and last will be protected by the keyword
> > const and cannot be changed in the code itself. And also the driver
> > needs some extra memory to do the calculation and extra conditions to
> > understand the length of each item spec. This is not efficient.
> >
> > To solve the issue and support usage of the following fix, a new OP
> > was introduced to calculate the spec and last values after applying
> > the mask inline.
> >
> > Signed-off-by: Bing Zhao <bingz@nvidia.com>
> > ---
>
> More detailed AI review found some things that still need addressing.
>
> On Wed, 3 Jun 2026 12:28:05 +0300, Bing Zhao wrote:
> > Subject: [PATCH v4] ethdev: support inline calculating masked item
> > value
>
> Error: byte-wise masking corrupts embedded pointers in deep-copy item
> types (RAW, FLEX, GENEVE_OPT).
>
> In rte_flow_conv_pattern(), the new mask application runs over the fixed
> item struct:
>
> size_t item_mask_size = mask ? rte_flow_conv_item_mask_size(src) :
> 0;
> ...
> size_t mask_size = RTE_MIN(ret, item_mask_size);
>
> for (j = 0; j < mask_size; j++)
> c_spec[j] &= mask[j];
>
> item_mask_size is rte_flow_desc_item[type].size, the size of the fixed
> item struct. For RTE_FLOW_ITEM_TYPE_RAW, FLEX, and GENEVE_OPT, that fixed
> struct ends in an embedded pointer that rte_flow_conv_item_spec() has just
> populated to point at the deep-copied trailing data
> (rte_flow_item_raw.pattern, rte_flow_item_flex.pattern,
> rte_flow_item_geneve_opt.data). Because the masked range covers the whole
> fixed struct, the loop ANDs the bytes of that pointer with the mask's
> corresponding bytes (typically a NULL mask pointer), zeroing or garbling
> it.
>
> The converted item's pattern/data pointer is clobbered while the copied
> payload it should reference is left unreachable. A consumer that follows
> conv->pattern then dereferences NULL or a corrupt address. Plain value
> conv->items
> (eth, ipv4, ...) are unaffected; only the deep-copy item types break,
> which is exactly what the test does not exercise.
>
> Suggested fix: do not blind-mask the entire fixed struct for items that
> carry an embedded pointer / desc_fn deep copy. Either skip masking when
> rte_flow_desc_item[type].desc_fn != NULL, or mask only the leading plain-
> data region and leave the pointer field (and trailing copied bytes)
> intact.
>
> Warning: the new test validates only an ETH pattern, so the
> RAW/FLEX/GENEVE_OPT path above is untested. A RAW item case would have
> surfaced the pointer corruption.
>
> Info: the Doxygen block for RTE_FLOW_CONV_OP_PATTERN_MASKED uses @p mask,
> @p spec, @p last, but those are item fields, not parameters of the op; the
> neighboring enum entries only document the @p src / @p dst types.
^ permalink raw reply
* Re: [PATCH 2/2] net/cnxk: add FEC get set and capability ops
From: Jerin Jacob @ 2026-06-09 5:06 UTC (permalink / raw)
To: rkudurumalla
Cc: Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori, Satha Rao,
Harman Kalra, dev, jerinj
In-Reply-To: <20260416120031.3553798-2-rkudurumalla@marvell.com>
On Thu, Apr 16, 2026 at 5:41 PM rkudurumalla <rkudurumalla@marvell.com> wrote:
>
> From: Rakesh Kudurumalla <rkudurumalla@marvell.com>
>
> Add ethdev FEC operations for cnxk NIX driver:
> - fec_get_capability: Report supported FEC modes per speed.
> If firmware provides supported FEC info, return actual
> capabilities for current link speed. Otherwise, fall back
> to a default capability table for common speeds.
> - fec_get: Query current FEC mode from link info
> - fec_set: Configure FEC mode on the link. AUTO mode
> defaults to Reed-Solomon FEC.
>
> Signed-off-by: Rakesh Kudurumalla <rkudurumalla@marvell.com>
Update doc/guides/nics/cnxk.rst and doc/guides/nics/features/cnxk* for
this new feature,.
^ permalink raw reply
* Re: [PATCH 2/2] common/cnxk: fix thread-unsafe NIX telemetry parsing
From: Jerin Jacob @ 2026-06-09 5:02 UTC (permalink / raw)
To: Stephen Hemminger
Cc: dev, stable, Nithin Dabilpuram, Kiran Kumar K, Sunil Kumar Kori,
Satha Rao, Harman Kalra, Gowrishankar Muthukrishnan, Jerin Jacob
In-Reply-To: <20260605224514.651081-3-stephen@networkplumber.org>
On Sat, Jun 6, 2026 at 4:15 AM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> cnxk_nix_tel_handle_info_x() backs the /cnxk/nix/{rq,cq,sq}/{info,ctx}
> telemetry commands and parsed its "<pcidev>,<queue_id>" parameter with
> strtok(), which keeps non-reentrant state and races when telemetry
> callbacks run on per-connection threads.
>
> Split the parameter with strchr() and parse the queue id with strtoul().
> While here, copy the full parameter (the length was capped at
> PCI_PRI_STR_SIZE + 1, truncating the id for longer device addresses) and
> reject non-numeric or out-of-range ids instead of letting strtol() alias
> them to queue 0.
>
> Fixes: af75aac78978 ("common/cnxk: support telemetry for NIX")
> Cc: stable@dpdk.org
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
@Nithin Dabilpuram Please review and Ack the series.
^ permalink raw reply
* [PATCH 1/1] mldev: fix incorrect captions for model_ops
From: Srikanth Yalavarthi @ 2026-06-09 5:00 UTC (permalink / raw)
To: Srikanth Yalavarthi, Anup Prabhu; +Cc: dev, jerinj, sshankarnara, ptakkar
Fixed incorrect captions in images depecting the
model_ops test flows.
Fixes: f6661e6d9a3a ("app/mldev: validate model operations")
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
doc/guides/tools/img/mldev_model_ops_subtest_a.svg | 4 ++--
doc/guides/tools/img/mldev_model_ops_subtest_b.svg | 4 ++--
doc/guides/tools/img/mldev_model_ops_subtest_d.svg | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/doc/guides/tools/img/mldev_model_ops_subtest_a.svg b/doc/guides/tools/img/mldev_model_ops_subtest_a.svg
index ed12cc5a05f..9b38300d1d7 100644
--- a/doc/guides/tools/img/mldev_model_ops_subtest_a.svg
+++ b/doc/guides/tools/img/mldev_model_ops_subtest_a.svg
@@ -10,7 +10,7 @@
version="1.1"
id="svg5"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
- sodipodi:docname="mldev_model_ops_subtest_d.svg"
+ sodipodi:docname="mldev_model_ops_subtest_a.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -407,7 +407,7 @@
id="tspan390"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.64444px;font-family:Arial;-inkscape-font-specification:'Arial Bold';fill:#000000;stroke-width:0.5"
x="-120.71075"
- y="220.77164">mldev: model_ops / subtest D</tspan></text>
+ y="220.77164">mldev: model_ops / subtest A</tspan></text>
<rect
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.448724;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect2164"
diff --git a/doc/guides/tools/img/mldev_model_ops_subtest_b.svg b/doc/guides/tools/img/mldev_model_ops_subtest_b.svg
index 173a2c6c059..d692b2ee023 100644
--- a/doc/guides/tools/img/mldev_model_ops_subtest_b.svg
+++ b/doc/guides/tools/img/mldev_model_ops_subtest_b.svg
@@ -10,7 +10,7 @@
version="1.1"
id="svg5"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
- sodipodi:docname="mldev_model_ops_subtest_a.svg"
+ sodipodi:docname="mldev_model_ops_subtest_b.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -410,7 +410,7 @@
id="tspan390"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.64444px;font-family:Arial;-inkscape-font-specification:'Arial Bold';fill:#000000;stroke-width:0.5"
x="-119.78458"
- y="220.32892">mldev: model_ops / subtest A</tspan></text>
+ y="220.32892">mldev: model_ops / subtest B</tspan></text>
<rect
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.442854;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers"
id="rect3967"
diff --git a/doc/guides/tools/img/mldev_model_ops_subtest_d.svg b/doc/guides/tools/img/mldev_model_ops_subtest_d.svg
index 3e2b89ad256..bf64f2b8360 100644
--- a/doc/guides/tools/img/mldev_model_ops_subtest_d.svg
+++ b/doc/guides/tools/img/mldev_model_ops_subtest_d.svg
@@ -10,7 +10,7 @@
version="1.1"
id="svg5"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
- sodipodi:docname="mldev_model_ops_subtest_b.svg"
+ sodipodi:docname="mldev_model_ops_subtest_d.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
@@ -411,7 +411,7 @@
id="tspan390"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.64444px;font-family:Arial;-inkscape-font-specification:'Arial Bold';fill:#000000;stroke-width:0.5"
x="-122.00021"
- y="222.26495">mldev: model_ops / subest B</tspan></text>
+ y="222.26495">mldev: model_ops / subtest D</tspan></text>
<rect
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.462341;stroke-linecap:round;stroke-linejoin:round;paint-order:stroke fill markers"
id="rect3475"
--
2.34.1
^ permalink raw reply related
* Re: [EXTERNAL] [PATCH dpdk] graph: replace circular buffer with priority-based bitmap scheduling
From: Jerin Jacob @ 2026-06-09 4:52 UTC (permalink / raw)
To: Robin Jarry
Cc: Jerin Jacob, dev@dpdk.org, Kiran Kumar Kokkilagadda,
Nithin Kumar Dabilpuram, Zhirun Yan, Vladimir Medvedkin,
Christophe Fontaine, David Marchand, Konstantin Ananyev,
Maxime Leroy
In-Reply-To: <DIMZ41ANY5TQ.3SXX22QGRY92R@redhat.com>
On Wed, May 20, 2026 at 3:20 AM Robin Jarry <rjarry@redhat.com> wrote:
>
> Hi Jerin,
>
> Jerin Jacob, May 19, 2026 at 12:25:
> > Some high-level comments:
> >
> > 1)What will be the performance overhead for graph walk. Try
> > app/test/test_graph_perf.c and l3fwd_graph
>
> I have made some measurements. There was a regression caused by
> systematic access to a cache line. This will be fixed in v2.
Thanks. We will review the v2.
> > 2)If priorities are same, Does it have similar performance with
> > existing code?
>
> Yes with v2. I have added a topo order as a fallback when all priorities
> are equal so that it behaves as previously.
>
> > 3)Does it have any effect on packet ordering on egress.i.e for a given
> > flow ingress order != egress order
>
> Some independent flows "may" be reordered but that depends on the
> topology, not the graph walk algorithm.
>
> For example, the following graph:
>
> +--------+
> | eth_in |
> +--------+
> / \
> v v
> +-------+ +---------+
> | ip_in | <-- | mpls_in |
> +-------+ +---------+
> |
> | ,------------.
> v v |
> +--------+ +----------+
> | ip_out | --> | ipip_out |
> +--------+ +----------+
> |
> v
> +---------+
> | eth_out |
> +---------+
>
> If you receive the following stream of packets in "eth_in":
>
> 1. Eth/IP
> 2. Eth/IP
> 3. Eth/MPLS/IP
> 4. Eth/MPLS/IP
> 5. Eth/MPLS/IP
> 6. Eth/IP (needs IPIP encap)
> 7. Eth/IP (needs IPIP encap)
> 8. Eth/IP
>
> The "eth_out" node will see:
>
> 1. Eth/IP
> 2. Eth/IP
> 3. Eth/IP
> 4. Eth/IP
> 5. Eth/IP
> * 8. Eth/IP <----------- reordered before 6 and 7
> 6. Eth/IP/IP
> 7. Eth/IP/IP
>
> With the FIFO circular buffer and with the new bitmap priority scheduler.
>
> The only difference with the bitmap system is that If you set "mpls_in"
> and "ip_out" higher priorities, the "ip_in" and "eth_out" nodes will be
> visited only once.
>
> > If there is performance regression we may need to consider new
> > RTE_GRAPH_MODEL_XXXXX to enable this feature
>
>
> --
> Robin
>
> > Times approximate.
>
^ permalink raw reply
* Re: [PATCH v2 2/3] event/cnxk: add pause to spinloops
From: Jerin Jacob @ 2026-06-09 4:50 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, Pavan Nikhilesh, Shijith Thotton
In-Reply-To: <20260608104426.6ceb4ad8@phoenix.local>
On Mon, Jun 8, 2026 at 11:14 PM Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Mon, 8 Jun 2026 21:19:20 +0530
> Jerin Jacob <jerinjacobk@gmail.com> wrote:
>
> > On Mon, Apr 13, 2026 at 10:36 PM Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On SMT systems when a spinloop is done without a pause
> > > it may cause excessive latency. This problem was found
> > > by the fix_empty_spinloops coccinelle script.
> > >
> > > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> >
> > rte_pause() translates to YIELD instruction. Since cnxk is an
> > integrated SoC and it is a single threaded core, it won't help on
> > anything other than adding one instruction bit more latency.
> > In general 3/3 devtool is good. Please send a it separate version so
> > that 3/3 patches can be merged through the main tree.
>
>
> It matters if your SOC has SMT where two cores are sharing
> and one core is waiting for its partner.
Yes. As I mentioned earlier, it is not cnxk is not SMT so it will not
be useful for cnxk.
^ permalink raw reply
* [PATCH 3/3] ml/cnxk: updated checks for number of MRVL layers
From: Srikanth Yalavarthi @ 2026-06-09 4:42 UTC (permalink / raw)
To: Srikanth Yalavarthi; +Cc: dev, jerinj, sshankarnara, ptakkar, aprabhu
In-Reply-To: <20260609044202.936153-1-syalavarthi@marvell.com>
Add checks to validate the current active MRVL layers
and increased the maximum number of layers supported
to 512 for LLVM only models.
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
drivers/ml/cnxk/cn10k_ml_ops.c | 6 +++---
drivers/ml/cnxk/cnxk_ml_dev.h | 4 ++--
drivers/ml/cnxk/cnxk_ml_io.h | 2 +-
drivers/ml/cnxk/cnxk_ml_ops.c | 14 +++++++-------
drivers/ml/cnxk/tvmrt_ml_model.c | 17 +++++++++++++++++
5 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index b30af7c7a44..00c0d87a6d6 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -624,15 +624,15 @@ cn10k_ml_layer_load(void *device, uint16_t model_id, const char *layer_name, uin
return ret;
/* Get index */
- for (idx = 0; idx < cnxk_mldev->max_nb_layers; idx++) {
+ for (idx = 0; idx < cnxk_mldev->max_mrvl_layers; idx++) {
if (!cnxk_mldev->index_map[idx].active) {
layer->index = idx;
break;
}
}
- if (idx >= cnxk_mldev->max_nb_layers) {
- plt_err("No slots available for model layers, model_id = %u, layer_id = %u",
+ if (idx >= cnxk_mldev->max_mrvl_layers) {
+ plt_err("No slots available for model MRVL layers, model_id = %u, layer_id = %u",
model->model_id, layer_id);
return -1;
}
diff --git a/drivers/ml/cnxk/cnxk_ml_dev.h b/drivers/ml/cnxk/cnxk_ml_dev.h
index e93d76d1af8..181a04737d7 100644
--- a/drivers/ml/cnxk/cnxk_ml_dev.h
+++ b/drivers/ml/cnxk/cnxk_ml_dev.h
@@ -93,9 +93,9 @@ struct cnxk_ml_dev {
#endif
/* Maximum number of layers */
- uint64_t max_nb_layers;
+ uint64_t max_mrvl_layers;
- /* Index map */
+ /* Index map for MRVL layers */
struct cnxk_ml_index_map *index_map;
};
diff --git a/drivers/ml/cnxk/cnxk_ml_io.h b/drivers/ml/cnxk/cnxk_ml_io.h
index 3ca852706f5..e6efd588f75 100644
--- a/drivers/ml/cnxk/cnxk_ml_io.h
+++ b/drivers/ml/cnxk/cnxk_ml_io.h
@@ -16,7 +16,7 @@
/* Maximum number of layers per model */
#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
-#define ML_CNXK_MODEL_MAX_LAYERS 128
+#define ML_CNXK_MODEL_MAX_LAYERS 512
#else
#define ML_CNXK_MODEL_MAX_LAYERS 1
#endif
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c
index 675cdaae2bd..dc057643068 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.c
+++ b/drivers/ml/cnxk/cnxk_ml_ops.c
@@ -636,30 +636,30 @@ cnxk_ml_dev_configure(struct rte_ml_dev *dev, const struct rte_ml_dev_config *co
/* Set device capabilities */
if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI)
- cnxk_mldev->max_nb_layers =
+ cnxk_mldev->max_mrvl_layers =
cnxk_mldev->cn10k_mldev.fw.req->cn10k_req.jd.fw_load.cap.s.max_models;
else
- cnxk_mldev->max_nb_layers = ML_CNXK_MAX_MODELS;
+ cnxk_mldev->max_mrvl_layers = 0;
cnxk_mldev->mldev->enqueue_burst = cnxk_ml_enqueue_burst;
cnxk_mldev->mldev->dequeue_burst = cnxk_ml_dequeue_burst;
cnxk_mldev->mldev->op_error_get = cnxk_ml_op_error_get;
/* Allocate and initialize index_map */
- if (cnxk_mldev->index_map == NULL) {
+ if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI && cnxk_mldev->index_map == NULL) {
cnxk_mldev->index_map =
rte_zmalloc("cnxk_ml_index_map",
- sizeof(struct cnxk_ml_index_map) * cnxk_mldev->max_nb_layers,
+ sizeof(struct cnxk_ml_index_map) * cnxk_mldev->max_mrvl_layers,
RTE_CACHE_LINE_SIZE);
if (cnxk_mldev->index_map == NULL) {
- plt_err("Failed to get memory for index_map, nb_layers %" PRIu64,
- cnxk_mldev->max_nb_layers);
+ plt_err("Failed to get memory for index_map, nb_mrvl_layers %" PRIu64,
+ cnxk_mldev->max_mrvl_layers);
ret = -ENOMEM;
goto error;
}
}
- for (i = 0; i < cnxk_mldev->max_nb_layers; i++)
+ for (i = 0; i < cnxk_mldev->max_mrvl_layers; i++)
cnxk_mldev->index_map[i].active = false;
/* Initialize xstats */
diff --git a/drivers/ml/cnxk/tvmrt_ml_model.c b/drivers/ml/cnxk/tvmrt_ml_model.c
index 9bff424f0d8..319c53a05b5 100644
--- a/drivers/ml/cnxk/tvmrt_ml_model.c
+++ b/drivers/ml/cnxk/tvmrt_ml_model.c
@@ -398,6 +398,7 @@ tvmrt_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg
int
tvmrt_ml_model_json_parse(struct cnxk_ml_model *model)
{
+ struct cnxk_ml_dev *cnxk_mldev = model->cnxk_mldev;
struct tvmrt_ml_param_names param_names;
json_error_t json_error;
json_t *json_parsed;
@@ -407,6 +408,7 @@ tvmrt_ml_model_json_parse(struct cnxk_ml_model *model)
json_t *json_node_row_ptr;
json_t *json_shape_values;
json_t *json_dtype_values;
+ uint16_t nb_active_mrvl_layers;
uint16_t nb_mrvl_layers;
uint16_t nb_llvm_layers;
DLDevice device;
@@ -511,6 +513,21 @@ tvmrt_ml_model_json_parse(struct cnxk_ml_model *model)
goto error;
}
+ nb_active_mrvl_layers = 0;
+ for (i = 0; i < cnxk_mldev->max_mrvl_layers; i++) {
+ if (cnxk_mldev->index_map[i].active)
+ nb_active_mrvl_layers++;
+ }
+
+ if (nb_active_mrvl_layers + nb_mrvl_layers > cnxk_mldev->max_mrvl_layers) {
+ ret = -ENOSPC;
+ plt_err("TVM runtime: Total MRVL layers (%u) exceeds maximum supported "
+ "MRVL layers (%" PRIu64 "), model_id = %u, error = %d",
+ nb_active_mrvl_layers + nb_mrvl_layers, cnxk_mldev->max_mrvl_layers,
+ model->model_id, ret);
+ goto error;
+ }
+
/* Set model subtype */
if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 1))
model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_MRVL;
--
2.34.1
^ permalink raw reply related
* [PATCH 2/3] ml/cnxk: rename tvm runtime module components
From: Srikanth Yalavarthi @ 2026-06-09 4:42 UTC (permalink / raw)
To: Srikanth Yalavarthi; +Cc: dev, jerinj, sshankarnara, ptakkar, aprabhu
In-Reply-To: <20260609044202.936153-1-syalavarthi@marvell.com>
Rename all TVM runtime specific files and functions with
tvmrt prefix. Retain mvtvm name prefix for functions and
files related to mvtvm vdev component.
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
drivers/ml/cnxk/cn10k_ml_model.c | 2 +-
drivers/ml/cnxk/cnxk_ml_dev.h | 4 +-
drivers/ml/cnxk/cnxk_ml_io.h | 6 +-
drivers/ml/cnxk/cnxk_ml_model.c | 4 +-
drivers/ml/cnxk/cnxk_ml_model.h | 12 +-
drivers/ml/cnxk/cnxk_ml_ops.c | 24 +-
drivers/ml/cnxk/cnxk_ml_ops.h | 10 +-
drivers/ml/cnxk/meson.build | 6 +-
drivers/ml/cnxk/mvtvm_ml_ops.c | 818 +-----------------
drivers/ml/cnxk/mvtvm_ml_ops.h | 66 --
drivers/ml/cnxk/mvtvm_ml_stubs.c | 97 ---
drivers/ml/cnxk/mvtvm_ml_stubs.h | 19 -
.../{mvtvm_ml_model.c => tvmrt_ml_model.c} | 269 +++---
.../{mvtvm_ml_model.h => tvmrt_ml_model.h} | 44 +-
drivers/ml/cnxk/tvmrt_ml_ops.c | 818 ++++++++++++++++++
drivers/ml/cnxk/tvmrt_ml_ops.h | 79 ++
drivers/ml/cnxk/tvmrt_ml_stubs.c | 106 +++
drivers/ml/cnxk/tvmrt_ml_stubs.h | 32 +
18 files changed, 1232 insertions(+), 1184 deletions(-)
rename drivers/ml/cnxk/{mvtvm_ml_model.c => tvmrt_ml_model.c} (72%)
rename drivers/ml/cnxk/{mvtvm_ml_model.h => tvmrt_ml_model.h} (78%)
create mode 100644 drivers/ml/cnxk/tvmrt_ml_ops.c
create mode 100644 drivers/ml/cnxk/tvmrt_ml_ops.h
create mode 100644 drivers/ml/cnxk/tvmrt_ml_stubs.c
create mode 100644 drivers/ml/cnxk/tvmrt_ml_stubs.h
diff --git a/drivers/ml/cnxk/cn10k_ml_model.c b/drivers/ml/cnxk/cn10k_ml_model.c
index 12a2dda800e..9cfecea4448 100644
--- a/drivers/ml/cnxk/cn10k_ml_model.c
+++ b/drivers/ml/cnxk/cn10k_ml_model.c
@@ -725,7 +725,7 @@ int
cn10k_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, uint16_t *layer_id)
{
if (model->type == ML_CNXK_MODEL_TYPE_TVM)
- return mvtvm_ml_model_get_layer_id(model, layer_name, layer_id);
+ return tvmrt_ml_model_get_layer_id(model, layer_name, layer_id);
*layer_id = 0;
diff --git a/drivers/ml/cnxk/cnxk_ml_dev.h b/drivers/ml/cnxk/cnxk_ml_dev.h
index 9e373e65715..e93d76d1af8 100644
--- a/drivers/ml/cnxk/cnxk_ml_dev.h
+++ b/drivers/ml/cnxk/cnxk_ml_dev.h
@@ -9,7 +9,7 @@
#include "cn10k_ml_dev.h"
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
#include "mvtvm_ml_dev.h"
#endif
@@ -87,7 +87,7 @@ struct cnxk_ml_dev {
/* CN10K device structure */
struct cn10k_ml_dev cn10k_mldev;
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
/* MVTVM device structure */
struct mvtvm_ml_dev mvtvm_mldev;
#endif
diff --git a/drivers/ml/cnxk/cnxk_ml_io.h b/drivers/ml/cnxk/cnxk_ml_io.h
index 17f5b4619f0..3ca852706f5 100644
--- a/drivers/ml/cnxk/cnxk_ml_io.h
+++ b/drivers/ml/cnxk/cnxk_ml_io.h
@@ -5,7 +5,7 @@
#ifndef _CNXK_ML_IO_H_
#define _CNXK_ML_IO_H_
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
#include <dlpack/dlpack.h>
#endif
@@ -15,7 +15,7 @@
#define ML_CNXK_MAX_MODELS 16
/* Maximum number of layers per model */
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
#define ML_CNXK_MODEL_MAX_LAYERS 128
#else
#define ML_CNXK_MODEL_MAX_LAYERS 1
@@ -59,7 +59,7 @@ struct cnxk_ml_io {
/* Zero point */
int64_t zero_point;
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
/* Shape - int64_t */
int64_t shape_i64[ML_CNXK_MODEL_MAX_DIMS];
diff --git a/drivers/ml/cnxk/cnxk_ml_model.c b/drivers/ml/cnxk/cnxk_ml_model.c
index ed6a1ed8665..442bc9460c0 100644
--- a/drivers/ml/cnxk/cnxk_ml_model.c
+++ b/drivers/ml/cnxk/cnxk_ml_model.c
@@ -16,7 +16,7 @@ cnxk_ml_model_get_type(struct rte_ml_model_params *params)
uint32_t payload_crc32c;
uint32_t header_crc32c;
- type = mvtvm_ml_model_type_get(params);
+ type = tvmrt_ml_model_type_get(params);
if (type == ML_CNXK_MODEL_TYPE_TVM)
return ML_CNXK_MODEL_TYPE_TVM;
else if (type == ML_CNXK_MODEL_TYPE_INVALID)
@@ -89,6 +89,6 @@ cnxk_ml_model_dump(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
if (layer->type == ML_CNXK_LAYER_TYPE_MRVL)
cn10k_ml_layer_print(cnxk_mldev, layer, fp);
else
- mvtvm_ml_layer_print(cnxk_mldev, layer, fp);
+ tvmrt_ml_layer_print(cnxk_mldev, layer, fp);
}
}
diff --git a/drivers/ml/cnxk/cnxk_ml_model.h b/drivers/ml/cnxk/cnxk_ml_model.h
index 1cd5ca1906a..59aea16f970 100644
--- a/drivers/ml/cnxk/cnxk_ml_model.h
+++ b/drivers/ml/cnxk/cnxk_ml_model.h
@@ -11,10 +11,10 @@
#include "cn10k_ml_model.h"
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
-#include "mvtvm_ml_model.h"
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
+#include "tvmrt_ml_model.h"
#else
-#include "mvtvm_ml_stubs.h"
+#include "tvmrt_ml_stubs.h"
#endif
#include "cnxk_ml_io.h"
@@ -152,9 +152,9 @@ struct cnxk_ml_model {
/* Model specific data - glow */
struct cn10k_ml_model_data glow;
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
- /* Model type specific data - mvtvm */
- struct mvtvm_ml_model_data mvtvm;
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
+ /* Model type specific data - tvmrt */
+ struct tvmrt_ml_model_data tvmrt;
#endif
};
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c
index 938982c7556..675cdaae2bd 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.c
+++ b/drivers/ml/cnxk/cnxk_ml_ops.c
@@ -250,7 +250,7 @@ cnxk_ml_xstats_model_name_update(struct cnxk_ml_dev *cnxk_mldev, uint16_t model_
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
cn10k_ml_xstat_model_name_set(cnxk_mldev, model, stat_id, i, suffix);
else
- mvtvm_ml_model_xstat_name_set(cnxk_mldev, model, stat_id, i, suffix);
+ tvmrt_ml_model_xstat_name_set(cnxk_mldev, model, stat_id, i, suffix);
stat_id++;
}
@@ -312,7 +312,7 @@ cnxk_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, uint16_t obj_idx, int32_
goto exit_xstats;
model_xstats:
- value = mvtvm_ml_model_xstat_get(cnxk_mldev, model, type);
+ value = tvmrt_ml_model_xstat_get(cnxk_mldev, model, type);
exit_xstats:
roc_clk_freq_get(&rclk_freq, &sclk_freq);
@@ -1211,7 +1211,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
if (type == ML_CNXK_MODEL_TYPE_GLOW)
ret = cn10k_ml_model_load(cnxk_mldev, params, model);
else
- ret = mvtvm_ml_model_load(cnxk_mldev, params, model);
+ ret = tvmrt_ml_model_load(cnxk_mldev, params, model);
if (ret != 0)
goto error;
@@ -1225,7 +1225,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
total_wb_pages = total_wb_pages + model->layer[layer_id].glow.ocm_map.wb_pages;
max_scratch_pages = PLT_MAX(max_scratch_pages,
model->layer[layer_id].glow.ocm_map.scratch_pages);
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
} else {
for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) {
@@ -1247,7 +1247,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
plt_ml_dbg("layer_id = %u: wb_pages = %u, scratch_pages = %u", layer_id,
model->layer[layer_id].glow.ocm_map.wb_pages,
model->layer[layer_id].glow.ocm_map.scratch_pages);
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
} else {
for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) {
@@ -1263,9 +1263,9 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
cn10k_ml_model_unload(cnxk_mldev, model);
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
else {
- mvtvm_ml_model_unload(cnxk_mldev, model);
+ tvmrt_ml_model_unload(cnxk_mldev, model);
return -ENOMEM;
}
#endif
@@ -1312,7 +1312,7 @@ cnxk_ml_model_unload(struct rte_ml_dev *dev, uint16_t model_id)
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
ret = cn10k_ml_model_unload(cnxk_mldev, model);
else
- ret = mvtvm_ml_model_unload(cnxk_mldev, model);
+ ret = tvmrt_ml_model_unload(cnxk_mldev, model);
if (ret != 0)
return ret;
@@ -1343,7 +1343,7 @@ cnxk_ml_model_start(struct rte_ml_dev *dev, uint16_t model_id)
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
return cn10k_ml_model_start(cnxk_mldev, model);
else
- return mvtvm_ml_model_start(cnxk_mldev, model);
+ return tvmrt_ml_model_start(cnxk_mldev, model);
return 0;
}
@@ -1368,7 +1368,7 @@ cnxk_ml_model_stop(struct rte_ml_dev *dev, uint16_t model_id)
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
return cn10k_ml_model_stop(cnxk_mldev, model);
else
- return mvtvm_ml_model_stop(cnxk_mldev, model);
+ return tvmrt_ml_model_stop(cnxk_mldev, model);
return 0;
}
@@ -1444,7 +1444,7 @@ cnxk_ml_io_quantize(struct rte_ml_dev *dev, uint16_t model_id, struct rte_ml_buf
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
info = cn10k_ml_model_io_info_get(model, 0);
else
- info = mvtvm_ml_model_io_info_get(model, 0);
+ info = tvmrt_ml_model_io_info_get(model, 0);
if (info == NULL)
return -EINVAL;
@@ -1500,7 +1500,7 @@ cnxk_ml_io_dequantize(struct rte_ml_dev *dev, uint16_t model_id, struct rte_ml_b
if (model->type == ML_CNXK_MODEL_TYPE_GLOW)
info = cn10k_ml_model_io_info_get(model, model->nb_layers - 1);
else
- info = mvtvm_ml_model_io_info_get(model, model->nb_layers - 1);
+ info = tvmrt_ml_model_io_info_get(model, model->nb_layers - 1);
if (info == NULL)
return -EINVAL;
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.h b/drivers/ml/cnxk/cnxk_ml_ops.h
index 7a79fec412e..ad10c3d45dc 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.h
+++ b/drivers/ml/cnxk/cnxk_ml_ops.h
@@ -12,10 +12,12 @@
#include "cn10k_ml_ops.h"
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
#include "mvtvm_ml_ops.h"
+#include "tvmrt_ml_ops.h"
#else
#include "mvtvm_ml_stubs.h"
+#include "tvmrt_ml_stubs.h"
#endif
/* Request structure */
@@ -25,9 +27,9 @@ struct __rte_aligned(ROC_ALIGN) cnxk_ml_req {
/* CN10K */
struct cn10k_ml_req cn10k_req;
-#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
- /* MVTVM */
- struct mvtvm_ml_req mvtvm_req;
+#ifdef RTE_MLDEV_CNXK_ENABLE_TVMRT
+ /* TVMRT */
+ struct tvmrt_ml_req tvmrt_req;
#endif
};
diff --git a/drivers/ml/cnxk/meson.build b/drivers/ml/cnxk/meson.build
index 5f078bd4fd7..da3cb7a2967 100644
--- a/drivers/ml/cnxk/meson.build
+++ b/drivers/ml/cnxk/meson.build
@@ -53,12 +53,13 @@ deps += ['mldev', 'common_cnxk', 'kvargs', 'hash']
if enable_mvtvm
-dpdk_conf.set('RTE_MLDEV_CNXK_ENABLE_MVTVM', 1)
+dpdk_conf.set('RTE_MLDEV_CNXK_ENABLE_TVMRT', 1)
sources += files(
'mvtvm_ml_dev.c',
'mvtvm_ml_ops.c',
- 'mvtvm_ml_model.c',
+ 'tvmrt_ml_ops.c',
+ 'tvmrt_ml_model.c',
)
ext_deps += jansson_dep
@@ -80,6 +81,7 @@ message('drivers/ml/cnxk: Disabled TVM model support')
sources += files(
'mvtvm_ml_stubs.c',
+ 'tvmrt_ml_stubs.c',
)
endif
diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.c b/drivers/ml/cnxk/mvtvm_ml_ops.c
index bc47a4bbd75..69b800c8421 100644
--- a/drivers/ml/cnxk/mvtvm_ml_ops.c
+++ b/drivers/ml/cnxk/mvtvm_ml_ops.c
@@ -2,189 +2,19 @@
* Copyright (c) 2023 Marvell.
*/
-#include <errno.h>
-#include <linux/limits.h>
-#include <stdbool.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <dlpack/dlpack.h>
-#include <jansson.h>
-
-#include <rte_common.h>
-#include <rte_cycles.h>
-#include <rte_mldev.h>
-#include <rte_mldev_pmd.h>
-
-#include <mldev_utils.h>
#include "cnxk_ml_dev.h"
-#include "cnxk_ml_model.h"
-#include "cnxk_ml_ops.h"
-#include "cnxk_ml_xstats.h"
-
-/* ML model macros */
-#define MVTVM_ML_MODEL_MEMZONE_NAME "ml_mvtvm_model_mz"
-
-/* Shared memory file descriptor name */
-#define ML_MODEL_SHMFD_NAME "mvtvm_shmfd"
-
-/* Shared memory file descriptor path */
-#define ML_MODEL_SHMFD_PATH "/proc/%d/fd/%d"
-
-static int
-mvtvm_ml_tvm_func_get(struct cnxk_ml_model *model, TVMModuleHandle module, const char *name,
- TVMFunctionHandle *func)
-{
- int ret;
-
- ret = TVMModGetFunction(module, name, 0, func);
- if (ret != 0) {
- plt_err("Model load failed, model_id = %u, ret = %d, msg = %s", model->model_id,
- ret, TVMGetLastError());
- return ret;
- }
-
- if (*func == NULL) {
- ret = -ENOENT;
- plt_err("Model load failed, model_id = %u, function '%s' not found",
- model->model_id, name);
- }
-
- return ret;
-}
-
-static int
-mvtvm_ml_tvm_func_call(struct cnxk_ml_model *model, TVMFunctionHandle func, const char *name,
- TVMValue *values, int *types, int num_args, TVMValue *ret_val, int *ret_type,
- int ret_type_code)
-{
- int ret;
-
- ret = TVMFuncCall(func, values, types, num_args, ret_val, ret_type);
- if (ret != 0) {
- plt_err("Error calling TVM function '%s', model_id = %u, ret = %d, msg = %s", name,
- model->model_id, ret, TVMGetLastError());
- return ret;
- }
-
- if (*ret_type != ret_type_code) {
- ret = -EINVAL;
- plt_err("TVM function '%s' returned unexpected type, model_id = %u, expected = %d, "
- "actual = %d",
- name, model->model_id, ret_type_code, *ret_type);
- }
-
- return ret;
-}
-
-static void
-mvtvm_ml_tvm_func_free(TVMFunctionHandle *func)
-{
- if ((func != NULL) && (*func != NULL)) {
- TVMFuncFree(*func);
- *func = NULL;
- }
-}
-
-static void
-mvtvm_ml_tvm_mod_free(TVMModuleHandle *mod)
-{
- if ((mod != NULL) && (*mod != NULL)) {
- TVMModFree(*mod);
- *mod = NULL;
- }
-}
-
-__rte_hot static void
-mvtvm_ml_set_poll_addr(struct cnxk_ml_req *req)
-{
- req->status = &req->mvtvm_req.status;
-}
-
-void
-mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- uint16_t stat_id, uint16_t entry, char *suffix)
-{
- snprintf(cnxk_mldev->xstats.entries[stat_id].map.name,
- sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s", model->name,
- model_xstats[entry].name, suffix);
-}
-
-#define ML_AVG_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count) \
- do { \
- value = 0; \
- for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
- value += model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_tot; \
- count += model->mvtvm.burst_xstats[qp_id].dequeued_count - \
- model->mvtvm.burst_xstats[qp_id].tvm_rt_reset_count; \
- } \
- if (count != 0) \
- value = value / count; \
- } while (0)
-
-#define ML_MIN_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count) \
- do { \
- value = UINT64_MAX; \
- for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
- value = PLT_MIN(value, \
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_min); \
- count += model->mvtvm.burst_xstats[qp_id].dequeued_count - \
- model->mvtvm.burst_xstats[qp_id].tvm_rt_reset_count; \
- } \
- if (count == 0) \
- value = 0; \
- } while (0)
-
-#define ML_MAX_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count) \
- do { \
- value = 0; \
- for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
- value = PLT_MAX(value, \
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_max); \
- count += model->mvtvm.burst_xstats[qp_id].dequeued_count - \
- model->mvtvm.burst_xstats[qp_id].tvm_rt_reset_count; \
- } \
- if (count == 0) \
- value = 0; \
- } while (0)
-
-uint64_t
-mvtvm_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- enum cnxk_ml_xstats_type type)
-{
- uint64_t count = 0;
- uint64_t value = 0;
- uint32_t qp_id;
-
- switch (type) {
- case avg_rt_latency:
- ML_AVG_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count);
- break;
- case min_rt_latency:
- ML_MIN_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count);
- break;
- case max_rt_latency:
- ML_MAX_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count);
- break;
- default:
- value = 0;
- }
-
- return value;
-}
+#include "mvtvm_ml_ops.h"
int
mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *dev_info)
{
- struct mvtvm_ml_dev *mvtvm_mldev;
+ struct mvtvm_ml_dev *tvmrt_mldev;
- mvtvm_mldev = &cnxk_mldev->mvtvm_mldev;
+ tvmrt_mldev = &cnxk_mldev->mvtvm_mldev;
- dev_info->max_queue_pairs = mvtvm_mldev->max_nb_qpairs;
+ dev_info->max_queue_pairs = tvmrt_mldev->max_nb_qpairs;
dev_info->max_desc = ML_MVTVM_MAX_DESC_PER_QP;
dev_info->max_io = ML_CNXK_MODEL_MAX_INPUT_OUTPUT;
dev_info->max_segments = ML_MVTVM_MAX_SEGMENTS;
@@ -201,643 +31,3 @@ mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp)
return 0;
}
-
-int
-mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
- struct cnxk_ml_model *model)
-{
- struct mvtvm_ml_model_object object[ML_MVTVM_MODEL_OBJECT_MAX];
- struct tvmrt_glow_callback *callback;
- char str[RTE_MEMZONE_NAMESIZE];
- char path[PATH_MAX];
- const struct plt_memzone *mz;
- size_t model_object_size = 0;
- size_t model_xstats_size = 0;
- uint64_t mz_size = 0;
- TVMFunctionHandle create_fn = NULL;
- TVMFunctionHandle register_cb_fn = NULL;
- TVMModuleHandle module_so = NULL;
- TVMByteArray tvm_params;
- TVMValue ret_value = {0};
- TVMValue arg_values[4] = {0};
- TVMValue tvm_arg_values[1] = {0};
- int ret_type = kTVMNullptr;
- int arg_types[4] = {0};
- int tvm_arg_types[1] = {0};
- DLDevice device;
- int ret;
-
- RTE_SET_USED(cnxk_mldev);
- model->mvtvm.fd = -1;
-
- ret = mvtvm_ml_model_blob_parse(params, object);
- if (ret != 0)
- return ret;
-
- model_object_size = RTE_ALIGN_CEIL(object[0].size, RTE_CACHE_LINE_MIN_SIZE) +
- RTE_ALIGN_CEIL(object[1].size, RTE_CACHE_LINE_MIN_SIZE) +
- RTE_ALIGN_CEIL(object[2].size, RTE_CACHE_LINE_MIN_SIZE);
-
- model_xstats_size =
- cnxk_mldev->mldev->data->nb_queue_pairs * sizeof(struct mvtvm_ml_model_xstats);
-
- mz_size += model_object_size + model_xstats_size;
-
- /* Allocate memzone for model object */
- snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", MVTVM_ML_MODEL_MEMZONE_NAME, model->model_id);
- mz = plt_memzone_reserve_aligned(str, mz_size, 0, ML_CN10K_ALIGN_SIZE);
- if (!mz) {
- plt_err("plt_memzone_reserve failed : %s", str);
- return -ENOMEM;
- }
-
- /* Copy mod.so */
- model->mvtvm.so.buffer = mz->addr;
- model->mvtvm.so.size = object[0].size;
- rte_memcpy(model->mvtvm.so.name, object[0].name, RTE_ML_STR_MAX);
- rte_memcpy(model->mvtvm.so.buffer, object[0].buffer, object[0].size);
- rte_free(object[0].buffer);
-
- /* Copy mod.json */
- model->mvtvm.json.buffer =
- RTE_PTR_ADD(model->mvtvm.so.buffer,
- RTE_ALIGN_CEIL(model->mvtvm.so.size, RTE_CACHE_LINE_MIN_SIZE));
- model->mvtvm.json.size = object[1].size;
- rte_memcpy(model->mvtvm.json.name, object[1].name, RTE_ML_STR_MAX);
- rte_memcpy(model->mvtvm.json.buffer, object[1].buffer, object[1].size);
- rte_free(object[1].buffer);
-
- /* Copy mod.params */
- model->mvtvm.params.buffer =
- RTE_PTR_ADD(model->mvtvm.json.buffer,
- RTE_ALIGN_CEIL(model->mvtvm.json.size, RTE_CACHE_LINE_MIN_SIZE));
- model->mvtvm.params.size = object[2].size;
- rte_memcpy(model->mvtvm.params.name, object[2].name, RTE_ML_STR_MAX);
- rte_memcpy(model->mvtvm.params.buffer, object[2].buffer, object[2].size);
- rte_free(object[2].buffer);
-
- ret = mvtvm_ml_model_json_parse(model);
- if (ret != 0)
- goto error;
-
- if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_VDEV &&
- model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) {
- plt_err("Unsupported model sub-type");
- ret = -ENOTSUP;
- goto error;
- }
-
- /* Set callback function array */
- if (model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) {
- callback = &model->mvtvm.cb;
- callback->tvmrt_glow_layer_load = cn10k_ml_layer_load;
- callback->tvmrt_glow_layer_unload = cn10k_ml_layer_unload;
- callback->tvmrt_io_alloc = cn10k_ml_io_alloc;
- callback->tvmrt_io_free = cn10k_ml_io_free;
- callback->tvmrt_malloc = cn10k_ml_malloc;
- callback->tvmrt_free = cn10k_ml_free;
- callback->tvmrt_quantize = mvtvm_ml_io_quantize;
- callback->tvmrt_dequantize = mvtvm_ml_io_dequantize;
- callback->tvmrt_inference = cn10k_ml_inference_sync;
- } else {
- callback = NULL;
- }
-
- /* Initialize model in TVM runtime */
- if (model->mvtvm.graph_module != NULL) {
- ret = -EBUSY;
- plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
- model->model_id, ret);
- goto error;
- }
-
- snprintf(path, sizeof(path), "%s_%d_%u", ML_MODEL_SHMFD_NAME, getpid(), model->model_id);
- model->mvtvm.fd = memfd_create(path, 0);
- if (model->mvtvm.fd < 0) {
- ret = (errno == 0) ? -EIO : -errno;
- plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
- model->model_id, ret);
- goto error;
- }
-
- if (write(model->mvtvm.fd, model->mvtvm.so.buffer, model->mvtvm.so.size) !=
- (ssize_t)model->mvtvm.so.size) {
- ret = (errno == 0) ? -EIO : -errno;
- plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
- model->model_id, ret);
- goto error;
- }
-
- if (lseek(model->mvtvm.fd, 0, SEEK_SET) < 0) {
- ret = (errno == 0) ? -EIO : -errno;
- plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
- model->model_id, ret);
- goto error;
- }
-
- snprintf(path, sizeof(path), ML_MODEL_SHMFD_PATH, getpid(), model->mvtvm.fd);
- ret = TVMModLoadFromFile(path, "so", &module_so);
- if (ret != 0) {
- plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
- model->model_id, ret, TVMGetLastError());
- goto error;
- }
-
- /* Set device info */
- device.device_type = kDLCPU;
- device.device_id = 0;
-
- if (callback != NULL) {
- ret = mvtvm_ml_tvm_func_get(model, module_so, "register_cb", ®ister_cb_fn);
- if (ret != 0)
- goto error;
-
- arg_values[0].v_handle = callback;
- arg_types[0] = kTVMOpaqueHandle;
- arg_values[1].v_handle = cnxk_mldev;
- arg_types[1] = kTVMOpaqueHandle;
- arg_values[2].v_int64 = model->model_id;
- arg_types[2] = kDLInt;
-
- ret = mvtvm_ml_tvm_func_call(model, register_cb_fn, "register_cb", arg_values,
- arg_types, 3, &ret_value, &ret_type, kTVMNullptr);
- if (ret != 0)
- goto error;
- }
-
- ret = TVMFuncGetGlobal("tvm.graph_executor.create", &create_fn);
- if (ret != 0) {
- plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
- model->model_id, ret, TVMGetLastError());
- goto error;
- }
-
- arg_values[0].v_str = (const char *)model->mvtvm.json.buffer;
- arg_types[0] = kTVMStr;
- arg_values[1].v_handle = module_so;
- arg_types[1] = kTVMModuleHandle;
- arg_values[2].v_int64 = device.device_type;
- arg_types[2] = kDLInt;
- arg_values[3].v_int64 = device.device_id;
- arg_types[3] = kDLInt;
-
- ret = mvtvm_ml_tvm_func_call(model, create_fn, "tvm.graph_executor.create", arg_values,
- arg_types, 4, &ret_value, &ret_type, kTVMModuleHandle);
- if (ret != 0)
- goto error;
- model->mvtvm.graph_module = ret_value.v_handle;
-
- ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "load_params",
- &model->mvtvm.load_params);
- if (ret != 0)
- goto error;
- ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_input_zero_copy",
- &model->mvtvm.set_input_zero_copy);
- if (ret != 0)
- goto error;
- ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_output_zero_copy",
- &model->mvtvm.set_output_zero_copy);
- if (ret != 0)
- goto error;
- ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "run", &model->mvtvm.run);
- if (ret != 0)
- goto error;
-
- mvtvm_ml_tvm_func_free(®ister_cb_fn);
- mvtvm_ml_tvm_mod_free(&module_so);
-
- /* Load model parameters into TVM runtime */
- tvm_params.data = (const char *)model->mvtvm.params.buffer;
- tvm_params.size = model->mvtvm.params.size;
- tvm_arg_values[0].v_handle = &tvm_params;
- tvm_arg_types[0] = kTVMBytes;
-
- ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.load_params, "load_params", tvm_arg_values,
- tvm_arg_types, 1, &ret_value, &ret_type, kTVMNullptr);
- if (ret != 0)
- goto error;
-
- /* Update model I/O data */
- mvtvm_ml_model_io_info_set(model);
-
- /* Set model info */
- mvtvm_ml_model_info_set(cnxk_mldev, model);
-
- /* Update model xstats name */
- cnxk_ml_xstats_model_name_update(cnxk_mldev, model->model_id);
-
- model->mvtvm.burst_xstats =
- RTE_PTR_ADD(model->mvtvm.params.buffer,
- RTE_ALIGN_CEIL(model->mvtvm.params.size, RTE_CACHE_LINE_MIN_SIZE));
-
- for (int qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) {
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_tot = 0;
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency = 0;
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_min = UINT64_MAX;
- model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_max = 0;
- model->mvtvm.burst_xstats[qp_id].tvm_rt_reset_count = 0;
- model->mvtvm.burst_xstats[qp_id].dequeued_count = 0;
- }
-
- /* Set model specific fast path functions */
- if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL) {
- model->enqueue_single = cn10k_ml_enqueue_single;
- model->result_update = cn10k_ml_result_update;
- model->set_error_code = cn10k_ml_set_error_code;
- model->set_poll_addr = cn10k_ml_set_poll_addr;
- model->op_error_get = cn10k_ml_op_error_get;
- } else {
- model->enqueue_single = mvtvm_ml_enqueue_single;
- model->result_update = mvtvm_ml_result_update;
- model->set_error_code = mvtvm_ml_set_error_code;
- model->set_poll_addr = mvtvm_ml_set_poll_addr;
- model->op_error_get = mvtvm_ml_op_error_get;
- }
-
- return 0;
-
-error:
- mvtvm_ml_tvm_func_free(®ister_cb_fn);
- if (model != NULL) {
- mvtvm_ml_tvm_func_free(&model->mvtvm.load_params);
- mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy);
- mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy);
- mvtvm_ml_tvm_func_free(&model->mvtvm.run);
- mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module);
- if (model->mvtvm.fd >= 0)
- close(model->mvtvm.fd);
- memset(&model->mvtvm, 0, sizeof(model->mvtvm));
- model->mvtvm.fd = -1;
- }
- mvtvm_ml_tvm_mod_free(&module_so);
- plt_memzone_free(mz);
-
- return ret;
-}
-
-int
-mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- char str[RTE_MEMZONE_NAMESIZE];
- const struct plt_memzone *mz;
-
- RTE_SET_USED(cnxk_mldev);
-
- /* Unload model from TVM runtime */
- if (model->model_id >= cnxk_mldev->mldev->data->nb_models)
- return -EINVAL;
-
- if (model->mvtvm.graph_module == NULL)
- return -EINVAL;
-
- mvtvm_ml_tvm_func_free(&model->mvtvm.load_params);
- mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy);
- mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy);
- mvtvm_ml_tvm_func_free(&model->mvtvm.run);
- mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module);
- if (model->mvtvm.fd >= 0)
- close(model->mvtvm.fd);
- memset(&model->mvtvm, 0, sizeof(model->mvtvm));
- model->mvtvm.fd = -1;
-
- snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", MVTVM_ML_MODEL_MEMZONE_NAME, model->model_id);
- mz = plt_memzone_lookup(str);
- if (mz == NULL) {
- plt_err("Memzone lookup failed for TVM model: model_id = %u, mz = %s",
- model->model_id, str);
- return -EINVAL;
- }
-
- return plt_memzone_free(mz);
-}
-
-int
-mvtvm_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- struct cnxk_ml_layer *layer;
-
- uint16_t layer_id = 0;
- int ret = 0;
-
-next_layer:
- layer = &model->layer[layer_id];
- if (layer->type == ML_CNXK_LAYER_TYPE_MRVL) {
- ret = cn10k_ml_layer_start(cnxk_mldev, model->model_id, layer->name);
- if (ret != 0) {
- plt_err("Layer start failed, model_id = %u, layer_name = %s, error = %d",
- model->model_id, layer->name, ret);
- return ret;
- }
- }
- layer_id++;
-
- if (layer_id < model->nb_layers)
- goto next_layer;
-
- return 0;
-}
-
-int
-mvtvm_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- struct cnxk_ml_layer *layer;
-
- uint16_t layer_id = 0;
- int ret = 0;
-
-next_layer:
- layer = &model->layer[layer_id];
- if (layer->type == ML_CNXK_LAYER_TYPE_MRVL) {
- ret = cn10k_ml_layer_stop(cnxk_mldev, model->model_id, layer->name);
- if (ret != 0) {
- plt_err("Layer stop failed, model_id = %u, layer_name = %s, error = %d",
- model->model_id, layer->name, ret);
- return ret;
- }
- }
- layer_id++;
-
- if (layer_id < model->nb_layers)
- goto next_layer;
-
- return 0;
-}
-
-int
-mvtvm_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name,
- const DLTensor **deq_tensor, void *qbuffer)
-{
- struct cnxk_ml_io_info *info = NULL;
- struct cnxk_ml_dev *cnxk_mldev;
- struct cnxk_ml_model *model;
- uint16_t layer_id = 0;
- uint8_t *lcl_dbuffer;
- uint8_t *lcl_qbuffer;
- uint32_t i;
- int ret;
-
-#ifdef CNXK_ML_DEV_DEBUG
- if ((device == NULL) || (deq_tensor == NULL) || (qbuffer == NULL))
- return -EINVAL;
-#endif
-
- cnxk_mldev = (struct cnxk_ml_dev *)device;
-
- model = cnxk_mldev->mldev->data->models[model_id];
-#ifdef CNXK_ML_DEV_DEBUG
- if (model == NULL) {
- plt_err("Invalid model_id = %u", model_id);
- return -EINVAL;
- }
-#endif
-
- /* Get layer id */
- for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
- if (strcmp(model->layer[layer_id].name, layer_name) == 0)
- break;
- }
-
-#ifdef CNXK_ML_DEV_DEBUG
- if (layer_id == model->nb_layers) {
- plt_err("Invalid layer name: %s", layer_name);
- return -EINVAL;
- }
-
- if (model->layer[layer_id].type != ML_CNXK_LAYER_TYPE_MRVL) {
- plt_err("Invalid layer name / type: %s", layer_name);
- return -EINVAL;
- }
-#endif
-
- info = &model->layer[layer_id].info;
- lcl_qbuffer = (uint8_t *)qbuffer;
-
- for (i = 0; i < info->nb_inputs; i++) {
- lcl_dbuffer = PLT_PTR_ADD(deq_tensor[i]->data, deq_tensor[i]->byte_offset);
-
- ret = cnxk_ml_io_quantize_single(&info->input[i], lcl_dbuffer, lcl_qbuffer);
- if (ret < 0)
- return ret;
-
- lcl_qbuffer += info->input[i].sz_q;
- }
-
- return 0;
-}
-
-int
-mvtvm_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name, void *qbuffer,
- const DLTensor **deq_tensor)
-{
- struct cnxk_ml_io_info *info = NULL;
- struct cnxk_ml_dev *cnxk_mldev;
- struct cnxk_ml_model *model;
- uint16_t layer_id = 0;
- uint8_t *lcl_dbuffer;
- uint8_t *lcl_qbuffer;
- uint32_t i;
- int ret;
-
-#ifdef CNXK_ML_DEV_DEBUG
- if ((device == NULL) || (deq_tensor == NULL) || (qbuffer == NULL))
- return -EINVAL;
-#endif
-
- cnxk_mldev = (struct cnxk_ml_dev *)device;
-
- model = cnxk_mldev->mldev->data->models[model_id];
-#ifdef CNXK_ML_DEV_DEBUG
- if (model == NULL) {
- plt_err("Invalid model_id = %u", model_id);
- return -EINVAL;
- }
-#endif
-
- for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
- if (strcmp(model->layer[layer_id].name, layer_name) == 0)
- break;
- }
-
-#ifdef CNXK_ML_DEV_DEBUG
- if (layer_id == model->nb_layers) {
- plt_err("Invalid layer name: %s", layer_name);
- return -EINVAL;
- }
-
- if (model->layer[layer_id].type != ML_CNXK_LAYER_TYPE_MRVL) {
- plt_err("Invalid layer name / type: %s", layer_name);
- return -EINVAL;
- }
-#endif
-
- info = &model->layer[layer_id].info;
- lcl_qbuffer = (uint8_t *)qbuffer;
-
- for (i = 0; i < info->nb_outputs; i++) {
- lcl_dbuffer = PLT_PTR_ADD(deq_tensor[i]->data, deq_tensor[i]->byte_offset);
-
- ret = cnxk_ml_io_dequantize_single(&info->output[i], lcl_qbuffer, lcl_dbuffer);
- if (ret < 0)
- return ret;
-
- lcl_qbuffer += info->output[i].sz_q;
- }
-
- return 0;
-}
-
-static int
-mvtvm_ml_model_run(struct cnxk_ml_model *model, struct rte_ml_op *op, struct cnxk_ml_req *req)
-{
- uint8_t i;
- struct mvtvm_ml_result *run_result;
- TVMValue arg_values[2] = {0};
- int arg_types[2] = {0};
- TVMValue ret_value = {0};
- int ret_type = kTVMNullptr;
- int ret = 0;
-
- rte_memcpy(req->mvtvm_req.input_tensor, model->mvtvm.input_tensor,
- model->mvtvm.info.nb_inputs * sizeof(DLTensor));
- for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
- req->mvtvm_req.input_tensor[i].data = op->input[i]->addr;
- req->mvtvm_req.input_tensor[i].byte_offset = 0;
- }
-
- rte_memcpy(req->mvtvm_req.output_tensor, model->mvtvm.output_tensor,
- model->mvtvm.info.nb_outputs * sizeof(DLTensor));
- for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
- req->mvtvm_req.output_tensor[i].data = op->output[i]->addr;
- req->mvtvm_req.output_tensor[i].byte_offset = 0;
- }
-
- run_result = &req->mvtvm_req.result;
- run_result->stats.start_ns = rte_get_tsc_cycles();
- run_result->error_code = 0;
-
- for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
- arg_values[0].v_int64 = i;
- arg_types[0] = kDLInt;
- arg_values[1].v_handle = &req->mvtvm_req.input_tensor[i];
- arg_types[1] = kTVMDLTensorHandle;
- ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_input_zero_copy,
- "set_input_zero_copy", arg_values, arg_types, 2,
- &ret_value, &ret_type, kTVMNullptr);
- if (ret != 0)
- goto out;
- }
-
- for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
- arg_values[0].v_int64 = i;
- arg_types[0] = kDLInt;
- arg_values[1].v_handle = &req->mvtvm_req.output_tensor[i];
- arg_types[1] = kTVMDLTensorHandle;
- ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_output_zero_copy,
- "set_output_zero_copy", arg_values, arg_types, 2,
- &ret_value, &ret_type, kTVMNullptr);
- if (ret != 0)
- goto out;
- }
-
- ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.run, "run", NULL, NULL, 0, &ret_value,
- &ret_type, kTVMNullptr);
- if (ret != 0)
- goto out;
-
-out:
- run_result->stats.end_ns = rte_get_tsc_cycles();
- req->mvtvm_req.status = 0x1;
-
- plt_write64(ML_CNXK_POLL_JOB_FINISH, req->status);
-
- if (ret != 0)
- run_result->error_code = -EIO;
-
- return 0;
-}
-
-__rte_hot void
-mvtvm_ml_set_error_code(struct cnxk_ml_req *req, uint64_t etype, uint64_t stype)
-{
- RTE_SET_USED(stype);
-
- req->mvtvm_req.result.error_code = etype;
-}
-
-__rte_hot int
-mvtvm_ml_op_error_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
- struct rte_ml_op_error *error)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(op);
- RTE_SET_USED(error);
-
- return 0;
-}
-
-__rte_hot bool
-mvtvm_ml_enqueue_single(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op, uint16_t layer_id,
- struct cnxk_ml_qp *qp, uint64_t head)
-{
- struct cnxk_ml_model *model;
- struct cnxk_ml_queue *queue;
- struct cnxk_ml_req *req;
-
- RTE_SET_USED(layer_id);
-
- queue = &qp->queue;
- req = &queue->reqs[head];
- model = cnxk_mldev->mldev->data->models[op->model_id];
-
- model->set_poll_addr(req);
- memset(&req->mvtvm_req.result, 0, sizeof(struct mvtvm_ml_result));
- req->mvtvm_req.result.error_code = 0x0;
- req->mvtvm_req.result.user_ptr = op->user_ptr;
-
- cnxk_ml_set_poll_ptr(req);
- mvtvm_ml_model_run(model, op, req);
- req->timeout = plt_tsc_cycles() + queue->wait_cycles;
- req->op = op;
-
- return true;
-}
-
-__rte_hot void
-mvtvm_ml_result_update(struct cnxk_ml_dev *cnxk_mldev, int qp_id, void *request)
-{
- struct mvtvm_ml_model_xstats *xstats;
- struct mvtvm_ml_result *result;
- struct cnxk_ml_model *model;
- struct cnxk_ml_req *req;
- uint64_t tvm_rt_latency;
- struct cnxk_ml_qp *qp;
- struct rte_ml_op *op;
-
- req = (struct cnxk_ml_req *)request;
- result = &req->mvtvm_req.result;
- op = req->op;
- qp = cnxk_mldev->mldev->data->queue_pairs[qp_id];
- op->impl_opaque = result->error_code;
-
- if (likely(result->error_code == 0)) {
- qp->stats.dequeued_count++;
- op->status = RTE_ML_OP_STATUS_SUCCESS;
-
- model = cnxk_mldev->mldev->data->models[op->model_id];
- xstats = &model->mvtvm.burst_xstats[qp_id];
-
- if (unlikely(xstats->dequeued_count == xstats->tvm_rt_reset_count)) {
- xstats->tvm_rt_latency_min = UINT64_MAX;
- xstats->tvm_rt_latency_max = 0;
- }
- tvm_rt_latency = result->stats.end_ns - result->stats.start_ns;
- xstats->tvm_rt_latency = tvm_rt_latency;
- xstats->tvm_rt_latency_tot += tvm_rt_latency;
- xstats->tvm_rt_latency_min = RTE_MIN(xstats->tvm_rt_latency_min, tvm_rt_latency);
- xstats->tvm_rt_latency_max = RTE_MAX(xstats->tvm_rt_latency_max, tvm_rt_latency);
- xstats->dequeued_count++;
- } else {
- qp->stats.dequeue_err_count++;
- op->status = RTE_ML_OP_STATUS_ERROR;
- }
-}
diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.h b/drivers/ml/cnxk/mvtvm_ml_ops.h
index 593f4585b3c..b83246517e7 100644
--- a/drivers/ml/cnxk/mvtvm_ml_ops.h
+++ b/drivers/ml/cnxk/mvtvm_ml_ops.h
@@ -5,77 +5,11 @@
#ifndef _MVTVM_ML_OPS_H_
#define _MVTVM_ML_OPS_H_
-#include <dlpack/dlpack.h>
-
#include <rte_mldev.h>
#include "cnxk_ml_xstats.h"
-#include "mvtvm_ml_model.h"
-
-struct cnxk_ml_dev;
-struct cnxk_ml_model;
-struct cnxk_ml_layer;
-struct cnxk_ml_qp;
-struct cnxk_ml_req;
-
-/* Inference stats */
-struct mvtvm_ml_stats {
- /* Start ns */
- uint64_t start_ns;
-
- /* Start ns */
- uint64_t end_ns;
-};
-
-/* Result structure */
-struct mvtvm_ml_result {
- /* Job error code */
- uint64_t error_code;
-
- /* Inference stats */
- struct mvtvm_ml_stats stats;
-
- /* User context pointer */
- void *user_ptr;
-};
-
-/* MVTVM specific request */
-struct mvtvm_ml_req {
- /* Input tensors */
- DLTensor input_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
-
- /* Output tensors */
- DLTensor output_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
-
- /* Status field for poll mode requests */
- volatile uint64_t status;
-
- /* Result */
- struct mvtvm_ml_result result;
-};
int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *mldev, struct rte_ml_dev_info *dev_info);
int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp);
-int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
- struct cnxk_ml_model *model);
-int mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-int mvtvm_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-int mvtvm_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-int mvtvm_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name,
- const DLTensor **deq_tensor, void *qbuffer);
-int mvtvm_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name, void *qbuffer,
- const DLTensor **deq_tensor);
-
-__rte_hot bool mvtvm_ml_enqueue_single(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
- uint16_t layer_id, struct cnxk_ml_qp *qp, uint64_t head);
-__rte_hot int mvtvm_ml_op_error_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
- struct rte_ml_op_error *error);
-__rte_hot void mvtvm_ml_result_update(struct cnxk_ml_dev *cnxk_mldev, int qp_id, void *request);
-__rte_hot void mvtvm_ml_set_error_code(struct cnxk_ml_req *req, uint64_t etype, uint64_t stype);
-
-void mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- uint16_t stat_id, uint16_t entry, char *suffix);
-uint64_t mvtvm_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- enum cnxk_ml_xstats_type type);
#endif /* _MVTVM_ML_OPS_H_ */
diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.c b/drivers/ml/cnxk/mvtvm_ml_stubs.c
index 7c13fac42d6..2341658657f 100644
--- a/drivers/ml/cnxk/mvtvm_ml_stubs.c
+++ b/drivers/ml/cnxk/mvtvm_ml_stubs.c
@@ -7,65 +7,6 @@
#include "mvtvm_ml_stubs.h"
#include "cnxk_ml_dev.h"
-#include "cnxk_ml_model.h"
-#include "cnxk_ml_xstats.h"
-
-enum cnxk_ml_model_type
-mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
-{
- RTE_SET_USED(params);
-
- return ML_CNXK_MODEL_TYPE_UNKNOWN;
-}
-
-int
-mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, uint16_t *layer_id)
-{
- RTE_SET_USED(model);
- RTE_SET_USED(layer_name);
- RTE_SET_USED(layer_id);
-
- return -EINVAL;
-}
-
-struct cnxk_ml_io_info *
-mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id)
-{
- RTE_SET_USED(model);
- RTE_SET_USED(layer_id);
-
- return NULL;
-}
-
-void
-mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(layer);
- RTE_SET_USED(fp);
-}
-
-void
-mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- uint16_t stat_id, uint16_t entry, char *suffix)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(model);
- RTE_SET_USED(stat_id);
- RTE_SET_USED(entry);
- RTE_SET_USED(suffix);
-}
-
-uint64_t
-mvtvm_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- enum cnxk_ml_xstats_type type)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(model);
- RTE_SET_USED(type);
-
- return 0;
-}
int
mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *dev_info)
@@ -84,41 +25,3 @@ mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp)
return -EINVAL;
}
-
-int
-mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
- struct cnxk_ml_model *model)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(params);
- RTE_SET_USED(model);
-
- return -EINVAL;
-}
-
-int
-mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(model);
-
- return -EINVAL;
-}
-
-int
-mvtvm_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(model);
-
- return -EINVAL;
-}
-
-int
-mvtvm_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(model);
-
- return -EINVAL;
-}
diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.h b/drivers/ml/cnxk/mvtvm_ml_stubs.h
index 15985a75bf4..0eebdbb1ed2 100644
--- a/drivers/ml/cnxk/mvtvm_ml_stubs.h
+++ b/drivers/ml/cnxk/mvtvm_ml_stubs.h
@@ -7,28 +7,9 @@
#include <rte_mldev.h>
-#include "cnxk_ml_xstats.h"
-
struct cnxk_ml_dev;
-struct cnxk_ml_model;
-struct cnxk_ml_layer;
-enum cnxk_ml_model_type mvtvm_ml_model_type_get(struct rte_ml_model_params *params);
int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *dev_info);
int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp);
-int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
- struct cnxk_ml_model *model);
-int mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-int mvtvm_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-int mvtvm_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-
-int mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
- uint16_t *layer_id);
-struct cnxk_ml_io_info *mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id);
-void mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp);
-void mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- uint16_t stat_id, uint16_t entry, char *suffix);
-uint64_t mvtvm_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
- enum cnxk_ml_xstats_type type);
#endif /* _MVTVM_ML_STUBS_H_ */
diff --git a/drivers/ml/cnxk/mvtvm_ml_model.c b/drivers/ml/cnxk/tvmrt_ml_model.c
similarity index 72%
rename from drivers/ml/cnxk/mvtvm_ml_model.c
rename to drivers/ml/cnxk/tvmrt_ml_model.c
index e1946607629..9bff424f0d8 100644
--- a/drivers/ml/cnxk/mvtvm_ml_model.c
+++ b/drivers/ml/cnxk/tvmrt_ml_model.c
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2023 Marvell.
+ * Copyright (c) 2026 Marvell.
*/
#include <errno.h>
@@ -22,13 +22,13 @@
#include "cnxk_ml_utils.h"
/* Objects list */
-char mvtvm_object_list[ML_MVTVM_MODEL_OBJECT_MAX][RTE_ML_STR_MAX] = {"mod.so", "mod.json",
- "mod.params"};
+static char tvmrt_object_list[ML_TVMRT_MODEL_OBJECT_MAX][RTE_ML_STR_MAX] = {"mod.so", "mod.json",
+ "mod.params"};
enum cnxk_ml_model_type
-mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
+tvmrt_ml_model_type_get(struct rte_ml_model_params *params)
{
- bool object_found[ML_MVTVM_MODEL_OBJECT_MAX] = {false, false, false};
+ bool object_found[ML_TVMRT_MODEL_OBJECT_MAX] = {false, false, false};
enum cnxk_ml_model_type model_type;
struct archive_entry *entry;
struct archive *a;
@@ -47,18 +47,18 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
/* Parse buffer for available objects */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
- for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
+ for (i = 0; i < ML_TVMRT_MODEL_OBJECT_MAX; i++) {
if (!object_found[i] &&
- (strcmp(archive_entry_pathname(entry), mvtvm_object_list[i]) == 0))
+ (strcmp(archive_entry_pathname(entry), tvmrt_object_list[i]) == 0))
object_found[i] = true;
}
archive_read_data_skip(a);
}
/* Check if all objects are available */
- for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
+ for (i = 0; i < ML_TVMRT_MODEL_OBJECT_MAX; i++) {
if (!object_found[i]) {
- plt_err("Object %s not found in archive!", mvtvm_object_list[i]);
+ plt_err("Object %s not found in archive!", tvmrt_object_list[i]);
model_type = ML_CNXK_MODEL_TYPE_INVALID;
goto cleanup;
}
@@ -74,15 +74,15 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
}
int
-mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_model_object *object)
+tvmrt_ml_model_blob_parse(struct rte_ml_model_params *params, struct tvmrt_ml_model_object *object)
{
- bool object_found[ML_MVTVM_MODEL_OBJECT_MAX] = {false, false, false};
+ bool object_found[ML_TVMRT_MODEL_OBJECT_MAX] = {false, false, false};
struct archive_entry *entry;
struct archive *a;
uint8_t i;
int ret;
- memset(object, 0, ML_MVTVM_MODEL_OBJECT_MAX * sizeof(*object));
+ memset(object, 0, ML_TVMRT_MODEL_OBJECT_MAX * sizeof(*object));
/* Open archive */
a = archive_read_new();
@@ -97,10 +97,10 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
/* Read archive */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
- for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
+ for (i = 0; i < ML_TVMRT_MODEL_OBJECT_MAX; i++) {
if (!object_found[i] &&
- (strcmp(archive_entry_pathname(entry), mvtvm_object_list[i]) == 0)) {
- memcpy(object[i].name, mvtvm_object_list[i], RTE_ML_STR_MAX);
+ (strcmp(archive_entry_pathname(entry), tvmrt_object_list[i]) == 0)) {
+ memcpy(object[i].name, tvmrt_object_list[i], RTE_ML_STR_MAX);
object[i].size = archive_entry_size(entry);
object[i].buffer = rte_malloc(NULL, object[i].size, 0);
if (object[i].buffer == NULL) {
@@ -122,9 +122,9 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
}
/* Check if all objects are parsed */
- for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
+ for (i = 0; i < ML_TVMRT_MODEL_OBJECT_MAX; i++) {
if (!object_found[i]) {
- plt_err("Object %s not found in archive!", mvtvm_object_list[i]);
+ plt_err("Object %s not found in archive!", tvmrt_object_list[i]);
ret = -EINVAL;
goto error;
}
@@ -133,7 +133,7 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
goto cleanup;
error:
- for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
+ for (i = 0; i < ML_TVMRT_MODEL_OBJECT_MAX; i++) {
if (object[i].buffer != NULL)
rte_free(object[i].buffer);
}
@@ -146,7 +146,7 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
}
int
-mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, uint16_t *layer_id)
+tvmrt_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, uint16_t *layer_id)
{
uint16_t i;
@@ -171,7 +171,7 @@ mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
}
static void
-mvtvm_ml_param_names_free(struct mvtvm_ml_param_names *param_names)
+tvmrt_ml_param_names_free(struct tvmrt_ml_param_names *param_names)
{
size_t i;
@@ -184,7 +184,7 @@ mvtvm_ml_param_names_free(struct mvtvm_ml_param_names *param_names)
}
static int
-mvtvm_ml_blob_read_u64(const uint8_t *blob, size_t blob_size, size_t *offset, uint64_t *value)
+tvmrt_ml_blob_read_u64(const uint8_t *blob, size_t blob_size, size_t *offset, uint64_t *value)
{
if (*offset + sizeof(*value) > blob_size)
return -EINVAL;
@@ -196,8 +196,8 @@ mvtvm_ml_blob_read_u64(const uint8_t *blob, size_t blob_size, size_t *offset, ui
}
static int
-mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
- struct mvtvm_ml_param_names *param_names)
+tvmrt_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
+ struct tvmrt_ml_param_names *param_names)
{
uint64_t magic = 0;
uint64_t reserved = 0;
@@ -208,18 +208,18 @@ mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
memset(param_names, 0, sizeof(*param_names));
- ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &magic);
+ ret = tvmrt_ml_blob_read_u64(blob, blob_size, &offset, &magic);
if (ret != 0)
return ret;
if (magic != TVM_NDARRAY_LIST_MAGIC)
return -EINVAL;
- ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &reserved);
+ ret = tvmrt_ml_blob_read_u64(blob, blob_size, &offset, &reserved);
if (ret != 0)
return ret;
- ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &count);
+ ret = tvmrt_ml_blob_read_u64(blob, blob_size, &offset, &count);
if (ret != 0)
return ret;
@@ -234,7 +234,7 @@ mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
for (i = 0; i < count; i++) {
uint64_t name_len = 0;
- ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &name_len);
+ ret = tvmrt_ml_blob_read_u64(blob, blob_size, &offset, &name_len);
if (ret != 0)
goto error;
@@ -261,12 +261,12 @@ mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
return 0;
error:
- mvtvm_ml_param_names_free(param_names);
+ tvmrt_ml_param_names_free(param_names);
return ret;
}
static int
-mvtvm_ml_dtype_parse(const char *dtype_str, DLDataType *dtype)
+tvmrt_ml_dtype_parse(const char *dtype_str, DLDataType *dtype)
{
const char *lanes_str;
char base[32] = {0};
@@ -321,7 +321,7 @@ mvtvm_ml_dtype_parse(const char *dtype_str, DLDataType *dtype)
}
static int
-mvtvm_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, const char *dtype_str,
+tvmrt_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, const char *dtype_str,
DLDevice device)
{
size_t i;
@@ -346,7 +346,7 @@ mvtvm_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, co
io->shape_i64[i] = json_integer_value(dim);
}
- ret = mvtvm_ml_dtype_parse(dtype_str, &io->datatype);
+ ret = tvmrt_ml_dtype_parse(dtype_str, &io->datatype);
if (ret != 0)
return ret;
@@ -357,8 +357,9 @@ mvtvm_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, co
return 0;
}
+
static int
-mvtvm_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg_nodes,
+tvmrt_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg_nodes,
json_t **heads, json_t **node_row_ptr, json_t **shape_values,
json_t **dtype_values)
{
@@ -395,9 +396,9 @@ mvtvm_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg
}
int
-mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
+tvmrt_ml_model_json_parse(struct cnxk_ml_model *model)
{
- struct mvtvm_ml_param_names param_names;
+ struct tvmrt_ml_param_names param_names;
json_error_t json_error;
json_t *json_parsed;
json_t *json_nodes;
@@ -414,16 +415,16 @@ mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
size_t j;
/* Parse param names from params buffer */
- ret = mvtvm_ml_param_names_parse(model->mvtvm.params.buffer, model->mvtvm.params.size,
+ ret = tvmrt_ml_param_names_parse(model->tvmrt.params.buffer, model->tvmrt.params.size,
¶m_names);
if (ret != 0)
return ret;
/* Load JSON graph (single load for both stages) */
- json_parsed = json_loadb((const char *)model->mvtvm.json.buffer, model->mvtvm.json.size, 0,
+ json_parsed = json_loadb((const char *)model->tvmrt.json.buffer, model->tvmrt.json.size, 0,
&json_error);
if (json_parsed == NULL) {
- mvtvm_ml_param_names_free(¶m_names);
+ tvmrt_ml_param_names_free(¶m_names);
plt_err("TVM runtime: Failed to parse JSON graph, model_id = %u", model->model_id);
return -EINVAL;
}
@@ -522,12 +523,12 @@ mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
device.device_type = kDLCPU;
device.device_id = 0;
- ret = mvtvm_ml_json_graph_get_arrays(json_parsed, &json_nodes, &json_arg_nodes, &json_heads,
+ ret = tvmrt_ml_json_graph_get_arrays(json_parsed, &json_nodes, &json_arg_nodes, &json_heads,
&json_node_row_ptr, &json_shape_values,
&json_dtype_values);
if (ret == 0) {
- model->mvtvm.info.nb_inputs = 0;
- model->mvtvm.info.nb_outputs = 0;
+ model->tvmrt.info.nb_inputs = 0;
+ model->tvmrt.info.nb_outputs = 0;
for (i = 0; i < json_array_size(json_arg_nodes); i++) {
json_t *arg_node_idx = json_array_get(json_arg_nodes, i);
@@ -561,18 +562,18 @@ mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
if (j < param_names.count)
continue;
- if (model->mvtvm.info.nb_inputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
+ if (model->tvmrt.info.nb_inputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
ret = -ENOTSUP;
break;
}
- ret = mvtvm_ml_model_io_set(
- &model->mvtvm.info.input[model->mvtvm.info.nb_inputs],
+ ret = tvmrt_ml_model_io_set(
+ &model->tvmrt.info.input[model->tvmrt.info.nb_inputs],
json_string_value(name), shape, json_string_value(dtype), device);
if (ret != 0)
break;
- model->mvtvm.info.nb_inputs++;
+ model->tvmrt.info.nb_inputs++;
}
for (i = 0; ret == 0 && i < json_array_size(json_heads); i++) {
@@ -641,18 +642,18 @@ mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
break;
}
- if (model->mvtvm.info.nb_outputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
+ if (model->tvmrt.info.nb_outputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
ret = -ENOTSUP;
break;
}
- ret = mvtvm_ml_model_io_set(
- &model->mvtvm.info.output[model->mvtvm.info.nb_outputs],
+ ret = tvmrt_ml_model_io_set(
+ &model->tvmrt.info.output[model->tvmrt.info.nb_outputs],
json_string_value(name), shape, json_string_value(dtype), device);
if (ret != 0)
break;
- model->mvtvm.info.nb_outputs++;
+ model->tvmrt.info.nb_outputs++;
}
}
@@ -661,17 +662,17 @@ mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
model->model_id, ret);
json_decref(json_parsed);
- mvtvm_ml_param_names_free(¶m_names);
+ tvmrt_ml_param_names_free(¶m_names);
return ret;
error:
json_decref(json_parsed);
- mvtvm_ml_param_names_free(¶m_names);
+ tvmrt_ml_param_names_free(¶m_names);
return ret;
}
static enum rte_ml_io_type
-mvtvm_ml_io_type_map(DLDataType dltype)
+tvmrt_ml_io_type_map(DLDataType dltype)
{
switch (dltype.code) {
case kDLInt:
@@ -714,7 +715,7 @@ mvtvm_ml_io_type_map(DLDataType dltype)
}
void
-mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
+tvmrt_ml_model_io_info_set(struct cnxk_ml_model *model)
{
int32_t i;
uint32_t j;
@@ -723,97 +724,97 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
goto tvm_mrvl_model;
/* Inputs, set for layer_id = 0 */
- model->mvtvm.info.total_input_sz_d = 0;
- model->mvtvm.info.total_input_sz_q = 0;
- for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
- model->mvtvm.info.input[i].dtype =
- mvtvm_ml_io_type_map(model->mvtvm.info.input[i].datatype);
- model->mvtvm.info.input[i].qtype =
- mvtvm_ml_io_type_map(model->mvtvm.info.input[i].model_datatype);
-
- model->mvtvm.info.input[i].nb_elements = 1;
- for (j = 0; j < model->mvtvm.info.input[i].nb_dims; j++) {
- model->mvtvm.info.input[i].shape[j] =
- PLT_U32_CAST(model->mvtvm.info.input[i].shape_i64[j]);
- model->mvtvm.info.input[i].nb_elements *=
- model->mvtvm.info.input[i].shape[j];
+ model->tvmrt.info.total_input_sz_d = 0;
+ model->tvmrt.info.total_input_sz_q = 0;
+ for (i = 0; i < model->tvmrt.info.nb_inputs; i++) {
+ model->tvmrt.info.input[i].dtype =
+ tvmrt_ml_io_type_map(model->tvmrt.info.input[i].datatype);
+ model->tvmrt.info.input[i].qtype =
+ tvmrt_ml_io_type_map(model->tvmrt.info.input[i].model_datatype);
+
+ model->tvmrt.info.input[i].nb_elements = 1;
+ for (j = 0; j < model->tvmrt.info.input[i].nb_dims; j++) {
+ model->tvmrt.info.input[i].shape[j] =
+ PLT_U32_CAST(model->tvmrt.info.input[i].shape_i64[j]);
+ model->tvmrt.info.input[i].nb_elements *=
+ model->tvmrt.info.input[i].shape[j];
}
- model->mvtvm.info.input[i].sz_d =
- model->mvtvm.info.input[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.input[i].dtype);
- model->mvtvm.info.input[i].sz_q =
- model->mvtvm.info.input[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.input[i].qtype);
+ model->tvmrt.info.input[i].sz_d =
+ model->tvmrt.info.input[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.input[i].dtype);
+ model->tvmrt.info.input[i].sz_q =
+ model->tvmrt.info.input[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.input[i].qtype);
- model->mvtvm.info.total_input_sz_d += model->mvtvm.info.input[i].sz_d;
- model->mvtvm.info.total_input_sz_q += model->mvtvm.info.input[i].sz_q;
+ model->tvmrt.info.total_input_sz_d += model->tvmrt.info.input[i].sz_d;
+ model->tvmrt.info.total_input_sz_q += model->tvmrt.info.input[i].sz_q;
- model->mvtvm.input_tensor[i].device = model->mvtvm.info.input[i].device;
- model->mvtvm.input_tensor[i].ndim = model->mvtvm.info.input[i].nb_dims;
- model->mvtvm.input_tensor[i].dtype = model->mvtvm.info.input[i].datatype;
- model->mvtvm.input_tensor[i].shape = model->mvtvm.info.input[i].shape_i64;
- model->mvtvm.input_tensor[i].strides = NULL;
- model->mvtvm.input_tensor[i].byte_offset = 0;
+ model->tvmrt.input_tensor[i].device = model->tvmrt.info.input[i].device;
+ model->tvmrt.input_tensor[i].ndim = model->tvmrt.info.input[i].nb_dims;
+ model->tvmrt.input_tensor[i].dtype = model->tvmrt.info.input[i].datatype;
+ model->tvmrt.input_tensor[i].shape = model->tvmrt.info.input[i].shape_i64;
+ model->tvmrt.input_tensor[i].strides = NULL;
+ model->tvmrt.input_tensor[i].byte_offset = 0;
plt_ml_dbg("model_id = %u, input[%u] - sz_d = %u sz_q = %u", model->model_id, i,
- model->mvtvm.info.input[i].sz_d, model->mvtvm.info.input[i].sz_q);
+ model->tvmrt.info.input[i].sz_d, model->tvmrt.info.input[i].sz_q);
}
/* Outputs, set for nb_layers - 1 */
- model->mvtvm.info.total_output_sz_d = 0;
- model->mvtvm.info.total_output_sz_q = 0;
- for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
- model->mvtvm.info.output[i].dtype =
- mvtvm_ml_io_type_map(model->mvtvm.info.output[i].datatype);
- model->mvtvm.info.output[i].qtype =
- mvtvm_ml_io_type_map(model->mvtvm.info.output[i].model_datatype);
-
- model->mvtvm.info.output[i].nb_elements = 1;
- for (j = 0; j < model->mvtvm.info.output[i].nb_dims; j++) {
- model->mvtvm.info.output[i].shape[j] =
- PLT_U32_CAST(model->mvtvm.info.output[i].shape_i64[j]);
- model->mvtvm.info.output[i].nb_elements *=
- model->mvtvm.info.output[i].shape[j];
+ model->tvmrt.info.total_output_sz_d = 0;
+ model->tvmrt.info.total_output_sz_q = 0;
+ for (i = 0; i < model->tvmrt.info.nb_outputs; i++) {
+ model->tvmrt.info.output[i].dtype =
+ tvmrt_ml_io_type_map(model->tvmrt.info.output[i].datatype);
+ model->tvmrt.info.output[i].qtype =
+ tvmrt_ml_io_type_map(model->tvmrt.info.output[i].model_datatype);
+
+ model->tvmrt.info.output[i].nb_elements = 1;
+ for (j = 0; j < model->tvmrt.info.output[i].nb_dims; j++) {
+ model->tvmrt.info.output[i].shape[j] =
+ PLT_U32_CAST(model->tvmrt.info.output[i].shape_i64[j]);
+ model->tvmrt.info.output[i].nb_elements *=
+ model->tvmrt.info.output[i].shape[j];
}
- model->mvtvm.info.output[i].sz_d =
- model->mvtvm.info.output[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.output[i].dtype);
- model->mvtvm.info.output[i].sz_q =
- model->mvtvm.info.output[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype);
+ model->tvmrt.info.output[i].sz_d =
+ model->tvmrt.info.output[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.output[i].dtype);
+ model->tvmrt.info.output[i].sz_q =
+ model->tvmrt.info.output[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.output[i].qtype);
- model->mvtvm.info.total_output_sz_d += model->mvtvm.info.output[i].sz_d;
- model->mvtvm.info.total_output_sz_q += model->mvtvm.info.output[i].sz_q;
+ model->tvmrt.info.total_output_sz_d += model->tvmrt.info.output[i].sz_d;
+ model->tvmrt.info.total_output_sz_q += model->tvmrt.info.output[i].sz_q;
- model->mvtvm.output_tensor[i].device = model->mvtvm.info.output[i].device;
- model->mvtvm.output_tensor[i].ndim = model->mvtvm.info.output[i].nb_dims;
- model->mvtvm.output_tensor[i].dtype = model->mvtvm.info.output[i].datatype;
- model->mvtvm.output_tensor[i].shape = model->mvtvm.info.output[i].shape_i64;
- model->mvtvm.output_tensor[i].strides = NULL;
- model->mvtvm.output_tensor[i].byte_offset = 0;
+ model->tvmrt.output_tensor[i].device = model->tvmrt.info.output[i].device;
+ model->tvmrt.output_tensor[i].ndim = model->tvmrt.info.output[i].nb_dims;
+ model->tvmrt.output_tensor[i].dtype = model->tvmrt.info.output[i].datatype;
+ model->tvmrt.output_tensor[i].shape = model->tvmrt.info.output[i].shape_i64;
+ model->tvmrt.output_tensor[i].strides = NULL;
+ model->tvmrt.output_tensor[i].byte_offset = 0;
plt_ml_dbg("model_id = %u, output[%u] - sz_d = %u sz_q = %u", model->model_id, i,
- model->mvtvm.info.output[i].sz_d, model->mvtvm.info.output[i].sz_q);
+ model->tvmrt.info.output[i].sz_d, model->tvmrt.info.output[i].sz_q);
}
return;
tvm_mrvl_model:
- cn10k_ml_layer_io_info_set(&model->mvtvm.info, &model->layer[0].glow.metadata);
+ cn10k_ml_layer_io_info_set(&model->tvmrt.info, &model->layer[0].glow.metadata);
}
struct cnxk_ml_io_info *
-mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id)
+tvmrt_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id)
{
RTE_SET_USED(layer_id);
- return &model->mvtvm.info;
+ return &model->tvmrt.info;
}
void
-mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+tvmrt_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
{
struct rte_ml_model_info *info;
struct rte_ml_io_info *output;
@@ -837,43 +838,43 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
info->io_layout = RTE_ML_IO_LAYOUT_SPLIT;
info->min_batches = model->batch_size;
info->max_batches = model->batch_size;
- info->nb_inputs = model->mvtvm.info.nb_inputs;
+ info->nb_inputs = model->tvmrt.info.nb_inputs;
info->input_info = input;
- info->nb_outputs = model->mvtvm.info.nb_outputs;
+ info->nb_outputs = model->tvmrt.info.nb_outputs;
info->output_info = output;
info->wb_size = 0;
/* Set input info */
for (i = 0; i < info->nb_inputs; i++) {
- rte_memcpy(input[i].name, model->mvtvm.info.input[i].name, MRVL_ML_INPUT_NAME_LEN);
- input[i].nb_dims = model->mvtvm.info.input[i].nb_dims;
- input[i].shape = &model->mvtvm.info.input[i].shape[0];
- input[i].type = model->mvtvm.info.input[i].qtype;
- input[i].nb_elements = model->mvtvm.info.input[i].nb_elements;
- input[i].size = model->mvtvm.info.input[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.input[i].qtype);
- input[i].scale = model->mvtvm.info.input[i].scale;
+ rte_memcpy(input[i].name, model->tvmrt.info.input[i].name, MRVL_ML_INPUT_NAME_LEN);
+ input[i].nb_dims = model->tvmrt.info.input[i].nb_dims;
+ input[i].shape = &model->tvmrt.info.input[i].shape[0];
+ input[i].type = model->tvmrt.info.input[i].qtype;
+ input[i].nb_elements = model->tvmrt.info.input[i].nb_elements;
+ input[i].size = model->tvmrt.info.input[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.input[i].qtype);
+ input[i].scale = model->tvmrt.info.input[i].scale;
input[i].zero_point = 0;
}
/* Set output info */
for (i = 0; i < info->nb_outputs; i++) {
- rte_memcpy(output[i].name, model->mvtvm.info.output[i].name,
+ rte_memcpy(output[i].name, model->tvmrt.info.output[i].name,
MRVL_ML_OUTPUT_NAME_LEN);
- output[i].nb_dims = model->mvtvm.info.output[i].nb_dims;
- output[i].shape = &model->mvtvm.info.output[i].shape[0];
- output[i].type = model->mvtvm.info.output[i].qtype;
- output[i].nb_elements = model->mvtvm.info.output[i].nb_elements;
- output[i].size = model->mvtvm.info.output[i].nb_elements *
- rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype);
- output[i].scale = model->mvtvm.info.output[i].scale;
+ output[i].nb_dims = model->tvmrt.info.output[i].nb_dims;
+ output[i].shape = &model->tvmrt.info.output[i].shape[0];
+ output[i].type = model->tvmrt.info.output[i].qtype;
+ output[i].nb_elements = model->tvmrt.info.output[i].nb_elements;
+ output[i].size = model->tvmrt.info.output[i].nb_elements *
+ rte_ml_io_type_size_get(model->tvmrt.info.output[i].qtype);
+ output[i].scale = model->tvmrt.info.output[i].scale;
output[i].zero_point = 0;
}
return;
tvm_mrvl_model:
- cn10k_ml_model_info_set(cnxk_mldev, model, &model->mvtvm.info,
+ cn10k_ml_model_info_set(cnxk_mldev, model, &model->tvmrt.info,
&model->layer[0].glow.metadata);
strlcpy(info->name, model->name, RTE_ML_STR_MAX);
@@ -882,7 +883,7 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
}
void
-mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp)
+tvmrt_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp)
{
char str[STR_LEN];
uint8_t i;
diff --git a/drivers/ml/cnxk/mvtvm_ml_model.h b/drivers/ml/cnxk/tvmrt_ml_model.h
similarity index 78%
rename from drivers/ml/cnxk/mvtvm_ml_model.h
rename to drivers/ml/cnxk/tvmrt_ml_model.h
index 1151b0a39ed..bf35dadb8a6 100644
--- a/drivers/ml/cnxk/mvtvm_ml_model.h
+++ b/drivers/ml/cnxk/tvmrt_ml_model.h
@@ -1,9 +1,9 @@
/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2023 Marvell.
+ * Copyright (c) 2026 Marvell.
*/
-#ifndef _MVTVM_ML_MODEL_H_
-#define _MVTVM_ML_MODEL_H_
+#ifndef _TVMRT_ML_MODEL_H_
+#define _TVMRT_ML_MODEL_H_
#include <dlpack/dlpack.h>
#include <jansson.h>
@@ -30,19 +30,19 @@ struct cnxk_ml_model;
struct cnxk_ml_layer;
/* Maximum number of objects per model */
-#define ML_MVTVM_MODEL_OBJECT_MAX 3
+#define ML_TVMRT_MODEL_OBJECT_MAX 3
/* Magic number for TVM parameter blobs. */
#define TVM_NDARRAY_LIST_MAGIC 0xF7E58D4F05049CB7ULL
/* TVM parameter names structure */
-struct mvtvm_ml_param_names {
+struct tvmrt_ml_param_names {
char **name;
size_t count;
};
/* TVM object / artifact info structure */
-struct mvtvm_ml_model_object {
+struct tvmrt_ml_model_object {
/* Name */
char name[RTE_ML_STR_MAX];
@@ -85,7 +85,7 @@ struct tvmrt_glow_callback {
};
/* Model fast-path stats */
-struct mvtvm_ml_model_xstats {
+struct tvmrt_ml_model_xstats {
/* Total TVM runtime latency, sum of all inferences */
uint64_t tvm_rt_latency_tot;
@@ -105,11 +105,11 @@ struct mvtvm_ml_model_xstats {
uint64_t tvm_rt_reset_count;
};
-struct mvtvm_ml_model_data {
+struct tvmrt_ml_model_data {
/* Model objects */
- struct mvtvm_ml_model_object so;
- struct mvtvm_ml_model_object json;
- struct mvtvm_ml_model_object params;
+ struct tvmrt_ml_model_object so;
+ struct tvmrt_ml_model_object json;
+ struct tvmrt_ml_model_object params;
/* TVM runtime callbacks */
struct tvmrt_glow_callback cb;
@@ -130,7 +130,7 @@ struct mvtvm_ml_model_data {
struct cnxk_ml_io_info info;
/* Stats for burst ops */
- struct mvtvm_ml_model_xstats *burst_xstats;
+ struct tvmrt_ml_model_xstats *burst_xstats;
/* Input Tensor */
DLTensor input_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
@@ -139,15 +139,15 @@ struct mvtvm_ml_model_data {
DLTensor output_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
};
-enum cnxk_ml_model_type mvtvm_ml_model_type_get(struct rte_ml_model_params *params);
-int mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params,
- struct mvtvm_ml_model_object *object);
-int mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
+enum cnxk_ml_model_type tvmrt_ml_model_type_get(struct rte_ml_model_params *params);
+int tvmrt_ml_model_blob_parse(struct rte_ml_model_params *params,
+ struct tvmrt_ml_model_object *object);
+int tvmrt_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
uint16_t *layer_id);
-void mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model);
-struct cnxk_ml_io_info *mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id);
-void mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
-void mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp);
-int mvtvm_ml_model_json_parse(struct cnxk_ml_model *model);
+void tvmrt_ml_model_io_info_set(struct cnxk_ml_model *model);
+struct cnxk_ml_io_info *tvmrt_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id);
+void tvmrt_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+void tvmrt_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp);
+int tvmrt_ml_model_json_parse(struct cnxk_ml_model *model);
-#endif /* _MVTVM_ML_MODEL_H_ */
+#endif /* _TVMRT_ML_MODEL_H_ */
diff --git a/drivers/ml/cnxk/tvmrt_ml_ops.c b/drivers/ml/cnxk/tvmrt_ml_ops.c
new file mode 100644
index 00000000000..f6b3a51c51e
--- /dev/null
+++ b/drivers/ml/cnxk/tvmrt_ml_ops.c
@@ -0,0 +1,818 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2026 Marvell.
+ */
+
+#include <errno.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <dlpack/dlpack.h>
+#include <jansson.h>
+
+#include <rte_common.h>
+#include <rte_cycles.h>
+#include <rte_mldev.h>
+#include <rte_mldev_pmd.h>
+
+#include <mldev_utils.h>
+
+#include "cnxk_ml_dev.h"
+#include "cnxk_ml_model.h"
+#include "cnxk_ml_ops.h"
+#include "cnxk_ml_xstats.h"
+
+/* ML model macros */
+#define TVMRT_ML_MODEL_MEMZONE_NAME "ml_tvmrt_model_mz"
+
+/* Shared memory file descriptor name */
+#define ML_MODEL_SHMFD_NAME "tvmrt_shmfd"
+
+/* Shared memory file descriptor path */
+#define ML_MODEL_SHMFD_PATH "/proc/%d/fd/%d"
+
+static int
+tvmrt_ml_tvm_func_get(struct cnxk_ml_model *model, TVMModuleHandle module, const char *name,
+ TVMFunctionHandle *func)
+{
+ int ret;
+
+ ret = TVMModGetFunction(module, name, 0, func);
+ if (ret != 0) {
+ plt_err("Model load failed, model_id = %u, ret = %d, msg = %s", model->model_id,
+ ret, TVMGetLastError());
+ return ret;
+ }
+
+ if (*func == NULL) {
+ ret = -ENOENT;
+ plt_err("Model load failed, model_id = %u, function '%s' not found",
+ model->model_id, name);
+ }
+
+ return ret;
+}
+
+static int
+tvmrt_ml_tvm_func_call(struct cnxk_ml_model *model, TVMFunctionHandle func, const char *name,
+ TVMValue *values, int *types, int num_args, TVMValue *ret_val, int *ret_type,
+ int ret_type_code)
+{
+ int ret;
+
+ ret = TVMFuncCall(func, values, types, num_args, ret_val, ret_type);
+ if (ret != 0) {
+ plt_err("Error calling TVM function '%s', model_id = %u, ret = %d, msg = %s", name,
+ model->model_id, ret, TVMGetLastError());
+ return ret;
+ }
+
+ if (*ret_type != ret_type_code) {
+ ret = -EINVAL;
+ plt_err("TVM function '%s' returned unexpected type, model_id = %u, expected = %d, "
+ "actual = %d",
+ name, model->model_id, ret_type_code, *ret_type);
+ }
+
+ return ret;
+}
+
+static void
+tvmrt_ml_tvm_func_free(TVMFunctionHandle *func)
+{
+ if ((func != NULL) && (*func != NULL)) {
+ TVMFuncFree(*func);
+ *func = NULL;
+ }
+}
+
+static void
+tvmrt_ml_tvm_mod_free(TVMModuleHandle *mod)
+{
+ if ((mod != NULL) && (*mod != NULL)) {
+ TVMModFree(*mod);
+ *mod = NULL;
+ }
+}
+
+__rte_hot static void
+tvmrt_ml_set_poll_addr(struct cnxk_ml_req *req)
+{
+ req->status = &req->tvmrt_req.status;
+}
+
+void
+tvmrt_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ uint16_t stat_id, uint16_t entry, char *suffix)
+{
+ snprintf(cnxk_mldev->xstats.entries[stat_id].map.name,
+ sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s", model->name,
+ model_xstats[entry].name, suffix);
+}
+
+#define ML_AVG_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count) \
+ do { \
+ value = 0; \
+ for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
+ value += model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_tot; \
+ count += model->tvmrt.burst_xstats[qp_id].dequeued_count - \
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_reset_count; \
+ } \
+ if (count != 0) \
+ value = value / count; \
+ } while (0)
+
+#define ML_MIN_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count) \
+ do { \
+ value = UINT64_MAX; \
+ for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
+ value = PLT_MIN(value, \
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_min); \
+ count += model->tvmrt.burst_xstats[qp_id].dequeued_count - \
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_reset_count; \
+ } \
+ if (count == 0) \
+ value = 0; \
+ } while (0)
+
+#define ML_MAX_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count) \
+ do { \
+ value = 0; \
+ for (qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) { \
+ value = PLT_MAX(value, \
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_max); \
+ count += model->tvmrt.burst_xstats[qp_id].dequeued_count - \
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_reset_count; \
+ } \
+ if (count == 0) \
+ value = 0; \
+ } while (0)
+
+uint64_t
+tvmrt_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ enum cnxk_ml_xstats_type type)
+{
+ uint64_t count = 0;
+ uint64_t value = 0;
+ uint32_t qp_id;
+
+ switch (type) {
+ case avg_rt_latency:
+ ML_AVG_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count);
+ break;
+ case min_rt_latency:
+ ML_MIN_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count);
+ break;
+ case max_rt_latency:
+ ML_MAX_FOREACH_QP_TVMRT(cnxk_mldev, model, qp_id, value, count);
+ break;
+ default:
+ value = 0;
+ }
+
+ return value;
+}
+
+int
+tvmrt_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
+ struct cnxk_ml_model *model)
+{
+ struct tvmrt_ml_model_object object[ML_TVMRT_MODEL_OBJECT_MAX];
+ struct tvmrt_glow_callback *callback;
+ char str[RTE_MEMZONE_NAMESIZE];
+ char path[PATH_MAX];
+ const struct plt_memzone *mz;
+ size_t model_object_size = 0;
+ size_t model_xstats_size = 0;
+ uint64_t mz_size = 0;
+ TVMFunctionHandle create_fn = NULL;
+ TVMFunctionHandle register_cb_fn = NULL;
+ TVMModuleHandle module_so = NULL;
+ TVMByteArray tvm_params;
+ TVMValue ret_value = {0};
+ TVMValue arg_values[4] = {0};
+ TVMValue tvm_arg_values[1] = {0};
+ int ret_type = kTVMNullptr;
+ int arg_types[4] = {0};
+ int tvm_arg_types[1] = {0};
+ DLDevice device;
+ int ret;
+
+ RTE_SET_USED(cnxk_mldev);
+ model->tvmrt.fd = -1;
+
+ ret = tvmrt_ml_model_blob_parse(params, object);
+ if (ret != 0)
+ return ret;
+
+ model_object_size = RTE_ALIGN_CEIL(object[0].size, RTE_CACHE_LINE_MIN_SIZE) +
+ RTE_ALIGN_CEIL(object[1].size, RTE_CACHE_LINE_MIN_SIZE) +
+ RTE_ALIGN_CEIL(object[2].size, RTE_CACHE_LINE_MIN_SIZE);
+
+ model_xstats_size =
+ cnxk_mldev->mldev->data->nb_queue_pairs * sizeof(struct tvmrt_ml_model_xstats);
+
+ mz_size += model_object_size + model_xstats_size;
+
+ /* Allocate memzone for model object */
+ snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", TVMRT_ML_MODEL_MEMZONE_NAME, model->model_id);
+ mz = plt_memzone_reserve_aligned(str, mz_size, 0, ML_CN10K_ALIGN_SIZE);
+ if (!mz) {
+ plt_err("plt_memzone_reserve failed : %s", str);
+ return -ENOMEM;
+ }
+
+ /* Copy mod.so */
+ model->tvmrt.so.buffer = mz->addr;
+ model->tvmrt.so.size = object[0].size;
+ rte_memcpy(model->tvmrt.so.name, object[0].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->tvmrt.so.buffer, object[0].buffer, object[0].size);
+ rte_free(object[0].buffer);
+
+ /* Copy mod.json */
+ model->tvmrt.json.buffer =
+ RTE_PTR_ADD(model->tvmrt.so.buffer,
+ RTE_ALIGN_CEIL(model->tvmrt.so.size, RTE_CACHE_LINE_MIN_SIZE));
+ model->tvmrt.json.size = object[1].size;
+ rte_memcpy(model->tvmrt.json.name, object[1].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->tvmrt.json.buffer, object[1].buffer, object[1].size);
+ rte_free(object[1].buffer);
+
+ /* Copy mod.params */
+ model->tvmrt.params.buffer =
+ RTE_PTR_ADD(model->tvmrt.json.buffer,
+ RTE_ALIGN_CEIL(model->tvmrt.json.size, RTE_CACHE_LINE_MIN_SIZE));
+ model->tvmrt.params.size = object[2].size;
+ rte_memcpy(model->tvmrt.params.name, object[2].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->tvmrt.params.buffer, object[2].buffer, object[2].size);
+ rte_free(object[2].buffer);
+
+ ret = tvmrt_ml_model_json_parse(model);
+ if (ret != 0)
+ goto error;
+
+ if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_VDEV &&
+ model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) {
+ plt_err("Unsupported model sub-type");
+ ret = -ENOTSUP;
+ goto error;
+ }
+
+ /* Set callback function array */
+ if (model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) {
+ callback = &model->tvmrt.cb;
+ callback->tvmrt_glow_layer_load = cn10k_ml_layer_load;
+ callback->tvmrt_glow_layer_unload = cn10k_ml_layer_unload;
+ callback->tvmrt_io_alloc = cn10k_ml_io_alloc;
+ callback->tvmrt_io_free = cn10k_ml_io_free;
+ callback->tvmrt_malloc = cn10k_ml_malloc;
+ callback->tvmrt_free = cn10k_ml_free;
+ callback->tvmrt_quantize = tvmrt_ml_io_quantize;
+ callback->tvmrt_dequantize = tvmrt_ml_io_dequantize;
+ callback->tvmrt_inference = cn10k_ml_inference_sync;
+ } else {
+ callback = NULL;
+ }
+
+ /* Initialize model in TVM runtime */
+ if (model->tvmrt.graph_module != NULL) {
+ ret = -EBUSY;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ snprintf(path, sizeof(path), "%s_%d_%u", ML_MODEL_SHMFD_NAME, getpid(), model->model_id);
+ model->tvmrt.fd = memfd_create(path, 0);
+ if (model->tvmrt.fd < 0) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ if (write(model->tvmrt.fd, model->tvmrt.so.buffer, model->tvmrt.so.size) !=
+ (ssize_t)model->tvmrt.so.size) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ if (lseek(model->tvmrt.fd, 0, SEEK_SET) < 0) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ snprintf(path, sizeof(path), ML_MODEL_SHMFD_PATH, getpid(), model->tvmrt.fd);
+ ret = TVMModLoadFromFile(path, "so", &module_so);
+ if (ret != 0) {
+ plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
+ model->model_id, ret, TVMGetLastError());
+ goto error;
+ }
+
+ /* Set device info */
+ device.device_type = kDLCPU;
+ device.device_id = 0;
+
+ if (callback != NULL) {
+ ret = tvmrt_ml_tvm_func_get(model, module_so, "register_cb", ®ister_cb_fn);
+ if (ret != 0)
+ goto error;
+
+ arg_values[0].v_handle = callback;
+ arg_types[0] = kTVMOpaqueHandle;
+ arg_values[1].v_handle = cnxk_mldev;
+ arg_types[1] = kTVMOpaqueHandle;
+ arg_values[2].v_int64 = model->model_id;
+ arg_types[2] = kDLInt;
+
+ ret = tvmrt_ml_tvm_func_call(model, register_cb_fn, "register_cb", arg_values,
+ arg_types, 3, &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto error;
+ }
+
+ ret = TVMFuncGetGlobal("tvm.graph_executor.create", &create_fn);
+ if (ret != 0) {
+ plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
+ model->model_id, ret, TVMGetLastError());
+ goto error;
+ }
+
+ arg_values[0].v_str = (const char *)model->tvmrt.json.buffer;
+ arg_types[0] = kTVMStr;
+ arg_values[1].v_handle = module_so;
+ arg_types[1] = kTVMModuleHandle;
+ arg_values[2].v_int64 = device.device_type;
+ arg_types[2] = kDLInt;
+ arg_values[3].v_int64 = device.device_id;
+ arg_types[3] = kDLInt;
+
+ ret = tvmrt_ml_tvm_func_call(model, create_fn, "tvm.graph_executor.create", arg_values,
+ arg_types, 4, &ret_value, &ret_type, kTVMModuleHandle);
+ if (ret != 0)
+ goto error;
+ model->tvmrt.graph_module = ret_value.v_handle;
+
+ ret = tvmrt_ml_tvm_func_get(model, model->tvmrt.graph_module, "load_params",
+ &model->tvmrt.load_params);
+ if (ret != 0)
+ goto error;
+ ret = tvmrt_ml_tvm_func_get(model, model->tvmrt.graph_module, "set_input_zero_copy",
+ &model->tvmrt.set_input_zero_copy);
+ if (ret != 0)
+ goto error;
+ ret = tvmrt_ml_tvm_func_get(model, model->tvmrt.graph_module, "set_output_zero_copy",
+ &model->tvmrt.set_output_zero_copy);
+ if (ret != 0)
+ goto error;
+ ret = tvmrt_ml_tvm_func_get(model, model->tvmrt.graph_module, "run", &model->tvmrt.run);
+ if (ret != 0)
+ goto error;
+
+ tvmrt_ml_tvm_func_free(®ister_cb_fn);
+ tvmrt_ml_tvm_mod_free(&module_so);
+
+ /* Load model parameters into TVM runtime */
+ tvm_params.data = (const char *)model->tvmrt.params.buffer;
+ tvm_params.size = model->tvmrt.params.size;
+ tvm_arg_values[0].v_handle = &tvm_params;
+ tvm_arg_types[0] = kTVMBytes;
+
+ ret = tvmrt_ml_tvm_func_call(model, model->tvmrt.load_params, "load_params", tvm_arg_values,
+ tvm_arg_types, 1, &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto error;
+
+ /* Update model I/O data */
+ tvmrt_ml_model_io_info_set(model);
+
+ /* Set model info */
+ tvmrt_ml_model_info_set(cnxk_mldev, model);
+
+ /* Update model xstats name */
+ cnxk_ml_xstats_model_name_update(cnxk_mldev, model->model_id);
+
+ model->tvmrt.burst_xstats =
+ RTE_PTR_ADD(model->tvmrt.params.buffer,
+ RTE_ALIGN_CEIL(model->tvmrt.params.size, RTE_CACHE_LINE_MIN_SIZE));
+
+ for (int qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) {
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_tot = 0;
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency = 0;
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_min = UINT64_MAX;
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_latency_max = 0;
+ model->tvmrt.burst_xstats[qp_id].tvm_rt_reset_count = 0;
+ model->tvmrt.burst_xstats[qp_id].dequeued_count = 0;
+ }
+
+ /* Set model specific fast path functions */
+ if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL) {
+ model->enqueue_single = cn10k_ml_enqueue_single;
+ model->result_update = cn10k_ml_result_update;
+ model->set_error_code = cn10k_ml_set_error_code;
+ model->set_poll_addr = cn10k_ml_set_poll_addr;
+ model->op_error_get = cn10k_ml_op_error_get;
+ } else {
+ model->enqueue_single = tvmrt_ml_enqueue_single;
+ model->result_update = tvmrt_ml_result_update;
+ model->set_error_code = tvmrt_ml_set_error_code;
+ model->set_poll_addr = tvmrt_ml_set_poll_addr;
+ model->op_error_get = tvmrt_ml_op_error_get;
+ }
+
+ return 0;
+
+error:
+ tvmrt_ml_tvm_func_free(®ister_cb_fn);
+ if (model != NULL) {
+ tvmrt_ml_tvm_func_free(&model->tvmrt.load_params);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.set_input_zero_copy);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.set_output_zero_copy);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.run);
+ tvmrt_ml_tvm_mod_free(&model->tvmrt.graph_module);
+ if (model->tvmrt.fd >= 0)
+ close(model->tvmrt.fd);
+ memset(&model->tvmrt, 0, sizeof(model->tvmrt));
+ model->tvmrt.fd = -1;
+ }
+ tvmrt_ml_tvm_mod_free(&module_so);
+ plt_memzone_free(mz);
+
+ return ret;
+}
+
+int
+tvmrt_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ char str[RTE_MEMZONE_NAMESIZE];
+ const struct plt_memzone *mz;
+
+ RTE_SET_USED(cnxk_mldev);
+
+ /* Unload model from TVM runtime */
+ if (model->model_id >= cnxk_mldev->mldev->data->nb_models)
+ return -EINVAL;
+
+ if (model->tvmrt.graph_module == NULL)
+ return -EINVAL;
+
+ tvmrt_ml_tvm_func_free(&model->tvmrt.load_params);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.set_input_zero_copy);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.set_output_zero_copy);
+ tvmrt_ml_tvm_func_free(&model->tvmrt.run);
+ tvmrt_ml_tvm_mod_free(&model->tvmrt.graph_module);
+ if (model->tvmrt.fd >= 0)
+ close(model->tvmrt.fd);
+ memset(&model->tvmrt, 0, sizeof(model->tvmrt));
+ model->tvmrt.fd = -1;
+
+ snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", TVMRT_ML_MODEL_MEMZONE_NAME, model->model_id);
+ mz = plt_memzone_lookup(str);
+ if (mz == NULL) {
+ plt_err("Memzone lookup failed for TVM model: model_id = %u, mz = %s",
+ model->model_id, str);
+ return -EINVAL;
+ }
+
+ return plt_memzone_free(mz);
+}
+
+int
+tvmrt_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ struct cnxk_ml_layer *layer;
+
+ uint16_t layer_id = 0;
+ int ret = 0;
+
+next_layer:
+ layer = &model->layer[layer_id];
+ if (layer->type == ML_CNXK_LAYER_TYPE_MRVL) {
+ ret = cn10k_ml_layer_start(cnxk_mldev, model->model_id, layer->name);
+ if (ret != 0) {
+ plt_err("Layer start failed, model_id = %u, layer_name = %s, error = %d",
+ model->model_id, layer->name, ret);
+ return ret;
+ }
+ }
+ layer_id++;
+
+ if (layer_id < model->nb_layers)
+ goto next_layer;
+
+ return 0;
+}
+
+int
+tvmrt_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ struct cnxk_ml_layer *layer;
+
+ uint16_t layer_id = 0;
+ int ret = 0;
+
+next_layer:
+ layer = &model->layer[layer_id];
+ if (layer->type == ML_CNXK_LAYER_TYPE_MRVL) {
+ ret = cn10k_ml_layer_stop(cnxk_mldev, model->model_id, layer->name);
+ if (ret != 0) {
+ plt_err("Layer stop failed, model_id = %u, layer_name = %s, error = %d",
+ model->model_id, layer->name, ret);
+ return ret;
+ }
+ }
+ layer_id++;
+
+ if (layer_id < model->nb_layers)
+ goto next_layer;
+
+ return 0;
+}
+
+int
+tvmrt_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name,
+ const DLTensor **deq_tensor, void *qbuffer)
+{
+ struct cnxk_ml_io_info *info = NULL;
+ struct cnxk_ml_dev *cnxk_mldev;
+ struct cnxk_ml_model *model;
+ uint16_t layer_id = 0;
+ uint8_t *lcl_dbuffer;
+ uint8_t *lcl_qbuffer;
+ uint32_t i;
+ int ret;
+
+#ifdef CNXK_ML_DEV_DEBUG
+ if ((device == NULL) || (deq_tensor == NULL) || (qbuffer == NULL))
+ return -EINVAL;
+#endif
+
+ cnxk_mldev = (struct cnxk_ml_dev *)device;
+
+ model = cnxk_mldev->mldev->data->models[model_id];
+#ifdef CNXK_ML_DEV_DEBUG
+ if (model == NULL) {
+ plt_err("Invalid model_id = %u", model_id);
+ return -EINVAL;
+ }
+#endif
+
+ /* Get layer id */
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
+ if (strcmp(model->layer[layer_id].name, layer_name) == 0)
+ break;
+ }
+
+#ifdef CNXK_ML_DEV_DEBUG
+ if (layer_id == model->nb_layers) {
+ plt_err("Invalid layer name: %s", layer_name);
+ return -EINVAL;
+ }
+
+ if (model->layer[layer_id].type != ML_CNXK_LAYER_TYPE_MRVL) {
+ plt_err("Invalid layer name / type: %s", layer_name);
+ return -EINVAL;
+ }
+#endif
+
+ info = &model->layer[layer_id].info;
+ lcl_qbuffer = (uint8_t *)qbuffer;
+
+ for (i = 0; i < info->nb_inputs; i++) {
+ lcl_dbuffer = PLT_PTR_ADD(deq_tensor[i]->data, deq_tensor[i]->byte_offset);
+
+ ret = cnxk_ml_io_quantize_single(&info->input[i], lcl_dbuffer, lcl_qbuffer);
+ if (ret < 0)
+ return ret;
+
+ lcl_qbuffer += info->input[i].sz_q;
+ }
+
+ return 0;
+}
+
+int
+tvmrt_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name, void *qbuffer,
+ const DLTensor **deq_tensor)
+{
+ struct cnxk_ml_io_info *info = NULL;
+ struct cnxk_ml_dev *cnxk_mldev;
+ struct cnxk_ml_model *model;
+ uint16_t layer_id = 0;
+ uint8_t *lcl_dbuffer;
+ uint8_t *lcl_qbuffer;
+ uint32_t i;
+ int ret;
+
+#ifdef CNXK_ML_DEV_DEBUG
+ if ((device == NULL) || (deq_tensor == NULL) || (qbuffer == NULL))
+ return -EINVAL;
+#endif
+
+ cnxk_mldev = (struct cnxk_ml_dev *)device;
+
+ model = cnxk_mldev->mldev->data->models[model_id];
+#ifdef CNXK_ML_DEV_DEBUG
+ if (model == NULL) {
+ plt_err("Invalid model_id = %u", model_id);
+ return -EINVAL;
+ }
+#endif
+
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
+ if (strcmp(model->layer[layer_id].name, layer_name) == 0)
+ break;
+ }
+
+#ifdef CNXK_ML_DEV_DEBUG
+ if (layer_id == model->nb_layers) {
+ plt_err("Invalid layer name: %s", layer_name);
+ return -EINVAL;
+ }
+
+ if (model->layer[layer_id].type != ML_CNXK_LAYER_TYPE_MRVL) {
+ plt_err("Invalid layer name / type: %s", layer_name);
+ return -EINVAL;
+ }
+#endif
+
+ info = &model->layer[layer_id].info;
+ lcl_qbuffer = (uint8_t *)qbuffer;
+
+ for (i = 0; i < info->nb_outputs; i++) {
+ lcl_dbuffer = PLT_PTR_ADD(deq_tensor[i]->data, deq_tensor[i]->byte_offset);
+
+ ret = cnxk_ml_io_dequantize_single(&info->output[i], lcl_qbuffer, lcl_dbuffer);
+ if (ret < 0)
+ return ret;
+
+ lcl_qbuffer += info->output[i].sz_q;
+ }
+
+ return 0;
+}
+
+static int
+tvmrt_ml_model_run(struct cnxk_ml_model *model, struct rte_ml_op *op, struct cnxk_ml_req *req)
+{
+ uint8_t i;
+ struct tvmrt_ml_result *run_result;
+ TVMValue arg_values[2] = {0};
+ int arg_types[2] = {0};
+ TVMValue ret_value = {0};
+ int ret_type = kTVMNullptr;
+ int ret = 0;
+
+ rte_memcpy(req->tvmrt_req.input_tensor, model->tvmrt.input_tensor,
+ model->tvmrt.info.nb_inputs * sizeof(DLTensor));
+ for (i = 0; i < model->tvmrt.info.nb_inputs; i++) {
+ req->tvmrt_req.input_tensor[i].data = op->input[i]->addr;
+ req->tvmrt_req.input_tensor[i].byte_offset = 0;
+ }
+
+ rte_memcpy(req->tvmrt_req.output_tensor, model->tvmrt.output_tensor,
+ model->tvmrt.info.nb_outputs * sizeof(DLTensor));
+ for (i = 0; i < model->tvmrt.info.nb_outputs; i++) {
+ req->tvmrt_req.output_tensor[i].data = op->output[i]->addr;
+ req->tvmrt_req.output_tensor[i].byte_offset = 0;
+ }
+
+ run_result = &req->tvmrt_req.result;
+ run_result->stats.start_ns = rte_get_tsc_cycles();
+ run_result->error_code = 0;
+
+ for (i = 0; i < model->tvmrt.info.nb_inputs; i++) {
+ arg_values[0].v_int64 = i;
+ arg_types[0] = kDLInt;
+ arg_values[1].v_handle = &req->tvmrt_req.input_tensor[i];
+ arg_types[1] = kTVMDLTensorHandle;
+ ret = tvmrt_ml_tvm_func_call(model, model->tvmrt.set_input_zero_copy,
+ "set_input_zero_copy", arg_values, arg_types, 2,
+ &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+ }
+
+ for (i = 0; i < model->tvmrt.info.nb_outputs; i++) {
+ arg_values[0].v_int64 = i;
+ arg_types[0] = kDLInt;
+ arg_values[1].v_handle = &req->tvmrt_req.output_tensor[i];
+ arg_types[1] = kTVMDLTensorHandle;
+ ret = tvmrt_ml_tvm_func_call(model, model->tvmrt.set_output_zero_copy,
+ "set_output_zero_copy", arg_values, arg_types, 2,
+ &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+ }
+
+ ret = tvmrt_ml_tvm_func_call(model, model->tvmrt.run, "run", NULL, NULL, 0, &ret_value,
+ &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+
+out:
+ run_result->stats.end_ns = rte_get_tsc_cycles();
+ req->tvmrt_req.status = 0x1;
+
+ plt_write64(ML_CNXK_POLL_JOB_FINISH, req->status);
+
+ if (ret != 0)
+ run_result->error_code = -EIO;
+
+ return 0;
+}
+
+__rte_hot void
+tvmrt_ml_set_error_code(struct cnxk_ml_req *req, uint64_t etype, uint64_t stype)
+{
+ RTE_SET_USED(stype);
+
+ req->tvmrt_req.result.error_code = etype;
+}
+
+__rte_hot int
+tvmrt_ml_op_error_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
+ struct rte_ml_op_error *error)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(op);
+ RTE_SET_USED(error);
+
+ return 0;
+}
+
+__rte_hot bool
+tvmrt_ml_enqueue_single(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op, uint16_t layer_id,
+ struct cnxk_ml_qp *qp, uint64_t head)
+{
+ struct cnxk_ml_model *model;
+ struct cnxk_ml_queue *queue;
+ struct cnxk_ml_req *req;
+
+ RTE_SET_USED(layer_id);
+
+ queue = &qp->queue;
+ req = &queue->reqs[head];
+ model = cnxk_mldev->mldev->data->models[op->model_id];
+
+ model->set_poll_addr(req);
+ memset(&req->tvmrt_req.result, 0, sizeof(struct tvmrt_ml_result));
+ req->tvmrt_req.result.error_code = 0x0;
+ req->tvmrt_req.result.user_ptr = op->user_ptr;
+
+ cnxk_ml_set_poll_ptr(req);
+ tvmrt_ml_model_run(model, op, req);
+ req->timeout = plt_tsc_cycles() + queue->wait_cycles;
+ req->op = op;
+
+ return true;
+}
+
+__rte_hot void
+tvmrt_ml_result_update(struct cnxk_ml_dev *cnxk_mldev, int qp_id, void *request)
+{
+ struct tvmrt_ml_model_xstats *xstats;
+ struct tvmrt_ml_result *result;
+ struct cnxk_ml_model *model;
+ struct cnxk_ml_req *req;
+ uint64_t tvm_rt_latency;
+ struct cnxk_ml_qp *qp;
+ struct rte_ml_op *op;
+
+ req = (struct cnxk_ml_req *)request;
+ result = &req->tvmrt_req.result;
+ op = req->op;
+ qp = cnxk_mldev->mldev->data->queue_pairs[qp_id];
+ op->impl_opaque = result->error_code;
+
+ if (likely(result->error_code == 0)) {
+ qp->stats.dequeued_count++;
+ op->status = RTE_ML_OP_STATUS_SUCCESS;
+
+ model = cnxk_mldev->mldev->data->models[op->model_id];
+ xstats = &model->tvmrt.burst_xstats[qp_id];
+
+ if (unlikely(xstats->dequeued_count == xstats->tvm_rt_reset_count)) {
+ xstats->tvm_rt_latency_min = UINT64_MAX;
+ xstats->tvm_rt_latency_max = 0;
+ }
+ tvm_rt_latency = result->stats.end_ns - result->stats.start_ns;
+ xstats->tvm_rt_latency = tvm_rt_latency;
+ xstats->tvm_rt_latency_tot += tvm_rt_latency;
+ xstats->tvm_rt_latency_min = RTE_MIN(xstats->tvm_rt_latency_min, tvm_rt_latency);
+ xstats->tvm_rt_latency_max = RTE_MAX(xstats->tvm_rt_latency_max, tvm_rt_latency);
+ xstats->dequeued_count++;
+ } else {
+ qp->stats.dequeue_err_count++;
+ op->status = RTE_ML_OP_STATUS_ERROR;
+ }
+}
diff --git a/drivers/ml/cnxk/tvmrt_ml_ops.h b/drivers/ml/cnxk/tvmrt_ml_ops.h
new file mode 100644
index 00000000000..f76f2ea000d
--- /dev/null
+++ b/drivers/ml/cnxk/tvmrt_ml_ops.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2026 Marvell.
+ */
+
+#ifndef _TVMRT_ML_OPS_H_
+#define _TVMRT_ML_OPS_H_
+
+#include <dlpack/dlpack.h>
+
+#include <rte_mldev.h>
+
+#include "cnxk_ml_xstats.h"
+#include "tvmrt_ml_model.h"
+
+struct cnxk_ml_dev;
+struct cnxk_ml_model;
+struct cnxk_ml_layer;
+struct cnxk_ml_qp;
+struct cnxk_ml_req;
+
+/* Inference stats */
+struct tvmrt_ml_stats {
+ /* Start ns */
+ uint64_t start_ns;
+
+ /* Start ns */
+ uint64_t end_ns;
+};
+
+/* Result structure */
+struct tvmrt_ml_result {
+ /* Job error code */
+ uint64_t error_code;
+
+ /* Inference stats */
+ struct tvmrt_ml_stats stats;
+
+ /* User context pointer */
+ void *user_ptr;
+};
+
+/* TVMRT specific request */
+struct tvmrt_ml_req {
+ /* Input tensors */
+ DLTensor input_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
+
+ /* Output tensors */
+ DLTensor output_tensor[ML_CNXK_MODEL_MAX_INPUT_OUTPUT];
+
+ /* Status field for poll mode requests */
+ volatile uint64_t status;
+
+ /* Result */
+ struct tvmrt_ml_result result;
+};
+
+int tvmrt_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
+ struct cnxk_ml_model *model);
+int tvmrt_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+int tvmrt_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+int tvmrt_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+int tvmrt_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name,
+ const DLTensor **deq_tensor, void *qbuffer);
+int tvmrt_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name, void *qbuffer,
+ const DLTensor **deq_tensor);
+
+__rte_hot bool tvmrt_ml_enqueue_single(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
+ uint16_t layer_id, struct cnxk_ml_qp *qp, uint64_t head);
+__rte_hot int tvmrt_ml_op_error_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_op *op,
+ struct rte_ml_op_error *error);
+__rte_hot void tvmrt_ml_result_update(struct cnxk_ml_dev *cnxk_mldev, int qp_id, void *request);
+__rte_hot void tvmrt_ml_set_error_code(struct cnxk_ml_req *req, uint64_t etype, uint64_t stype);
+
+void tvmrt_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ uint16_t stat_id, uint16_t entry, char *suffix);
+uint64_t tvmrt_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ enum cnxk_ml_xstats_type type);
+
+#endif /* _TVMRT_ML_OPS_H_ */
diff --git a/drivers/ml/cnxk/tvmrt_ml_stubs.c b/drivers/ml/cnxk/tvmrt_ml_stubs.c
new file mode 100644
index 00000000000..0b4e53b4327
--- /dev/null
+++ b/drivers/ml/cnxk/tvmrt_ml_stubs.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2026 Marvell.
+ */
+
+#include <rte_mldev.h>
+
+#include "tvmrt_ml_stubs.h"
+
+#include "cnxk_ml_dev.h"
+#include "cnxk_ml_model.h"
+#include "cnxk_ml_xstats.h"
+
+enum cnxk_ml_model_type
+tvmrt_ml_model_type_get(struct rte_ml_model_params *params)
+{
+ RTE_SET_USED(params);
+
+ return ML_CNXK_MODEL_TYPE_UNKNOWN;
+}
+
+int
+tvmrt_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name, uint16_t *layer_id)
+{
+ RTE_SET_USED(model);
+ RTE_SET_USED(layer_name);
+ RTE_SET_USED(layer_id);
+
+ return -EINVAL;
+}
+
+struct cnxk_ml_io_info *
+tvmrt_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id)
+{
+ RTE_SET_USED(model);
+ RTE_SET_USED(layer_id);
+
+ return NULL;
+}
+
+void
+tvmrt_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(layer);
+ RTE_SET_USED(fp);
+}
+
+void
+tvmrt_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ uint16_t stat_id, uint16_t entry, char *suffix)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(model);
+ RTE_SET_USED(stat_id);
+ RTE_SET_USED(entry);
+ RTE_SET_USED(suffix);
+}
+
+uint64_t
+tvmrt_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ enum cnxk_ml_xstats_type type)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(model);
+ RTE_SET_USED(type);
+
+ return 0;
+}
+
+int
+tvmrt_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
+ struct cnxk_ml_model *model)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(params);
+ RTE_SET_USED(model);
+
+ return -EINVAL;
+}
+
+int
+tvmrt_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(model);
+
+ return -EINVAL;
+}
+
+int
+tvmrt_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(model);
+
+ return -EINVAL;
+}
+
+int
+tvmrt_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
+{
+ RTE_SET_USED(cnxk_mldev);
+ RTE_SET_USED(model);
+
+ return -EINVAL;
+}
diff --git a/drivers/ml/cnxk/tvmrt_ml_stubs.h b/drivers/ml/cnxk/tvmrt_ml_stubs.h
new file mode 100644
index 00000000000..e0260d36514
--- /dev/null
+++ b/drivers/ml/cnxk/tvmrt_ml_stubs.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2026 Marvell.
+ */
+
+#ifndef _TVMRT_ML_STUBS_H_
+#define _TVMRT_ML_STUBS_H_
+
+#include <rte_mldev.h>
+
+#include "cnxk_ml_xstats.h"
+
+struct cnxk_ml_dev;
+struct cnxk_ml_model;
+struct cnxk_ml_layer;
+
+enum cnxk_ml_model_type tvmrt_ml_model_type_get(struct rte_ml_model_params *params);
+int tvmrt_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
+ struct cnxk_ml_model *model);
+int tvmrt_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+int tvmrt_ml_model_start(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+int tvmrt_ml_model_stop(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
+
+int tvmrt_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
+ uint16_t *layer_id);
+struct cnxk_ml_io_info *tvmrt_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id);
+void tvmrt_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp);
+void tvmrt_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ uint16_t stat_id, uint16_t entry, char *suffix);
+uint64_t tvmrt_ml_model_xstat_get(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model,
+ enum cnxk_ml_xstats_type type);
+
+#endif /* _TVMRT_ML_STUBS_H_ */
--
2.34.1
^ permalink raw reply related
* [PATCH 1/3] ml/cnxk: update driver to use TVM C runtime
From: Srikanth Yalavarthi @ 2026-06-09 4:42 UTC (permalink / raw)
To: Srikanth Yalavarthi; +Cc: dev, jerinj, sshankarnara, ptakkar, aprabhu
Updated MVTVM layer of the driver to call TVM C runtime
API functions, instead on the TVMDP wrapper library APIs.
Drop all dependencies on TVMDP wrapper library.
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
doc/guides/mldevs/cnxk.rst | 35 +-
drivers/ml/cnxk/cnxk_ml_io.h | 20 +-
drivers/ml/cnxk/cnxk_ml_ops.c | 12 +-
drivers/ml/cnxk/meson.build | 14 +-
drivers/ml/cnxk/mvtvm_ml_dev.h | 3 -
drivers/ml/cnxk/mvtvm_ml_model.c | 638 ++++++++++++++++++++++++++++---
drivers/ml/cnxk/mvtvm_ml_model.h | 81 +++-
drivers/ml/cnxk/mvtvm_ml_ops.c | 440 ++++++++++++++-------
drivers/ml/cnxk/mvtvm_ml_ops.h | 5 +-
drivers/ml/cnxk/mvtvm_ml_stubs.c | 17 -
drivers/ml/cnxk/mvtvm_ml_stubs.h | 2 -
11 files changed, 985 insertions(+), 282 deletions(-)
diff --git a/doc/guides/mldevs/cnxk.rst b/doc/guides/mldevs/cnxk.rst
index fc1bcd9cdb4..17e58d81c0b 100644
--- a/doc/guides/mldevs/cnxk.rst
+++ b/doc/guides/mldevs/cnxk.rst
@@ -111,13 +111,13 @@ on CPU cores or hardware accelerators.
.. note::
- DPDK CNXK ML driver requires TVM version 0.10.0
+ DPDK CNXK ML driver requires TVM version legacy-v0.19.post branch.
.. code-block:: console
git clone https://github.com/apache/tvm.git
cd tvm
- git checkout v0.11.0 -b v0.11.0
+ git checkout legacy-v0.19.post -b legacy-v0.19.post
git submodule update --init
cmake -S ./ -B build \
-DCMAKE_INSTALL_PREFIX=<install_prefix> \
@@ -135,37 +135,6 @@ When cross-compiling, more options must be provided to CMake:
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY
-TVMDP
-~~~~~
-
- Marvell's `TVM Dataplane Library <https://github.com/MarvellEmbeddedProcessors/tvmdp>`_
- works as an interface between TVM runtime and DPDK drivers.
- TVMDP library provides a simplified C interface
- for TVM's runtime based on C++.
-
-.. note::
-
- TVMDP library is dependent on TVM, dlpack, jansson and dmlc-core libraries.
-
-.. code-block:: console
-
- git clone https://github.com/MarvellEmbeddedProcessors/tvmdp.git
- cd tvmdp
- git checkout main
- cmake -S ./ -B build \
- -DCMAKE_INSTALL_PREFIX=<install_prefix> \
- -DBUILD_SHARED_LIBS=ON
- make -C build
- make -C build install
-
-When cross-compiling, more options must be provided to CMake:
-
-.. code-block:: console
-
- -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \
- -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
- -DCMAKE_FIND_ROOT_PATH=<install_prefix>
-
libarchive
~~~~~~~~~~
diff --git a/drivers/ml/cnxk/cnxk_ml_io.h b/drivers/ml/cnxk/cnxk_ml_io.h
index 83329c237aa..17f5b4619f0 100644
--- a/drivers/ml/cnxk/cnxk_ml_io.h
+++ b/drivers/ml/cnxk/cnxk_ml_io.h
@@ -6,7 +6,7 @@
#define _CNXK_ML_IO_H_
#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
-#include <tvmdp.h>
+#include <dlpack/dlpack.h>
#endif
#include <rte_mldev.h>
@@ -16,7 +16,7 @@
/* Maximum number of layers per model */
#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
-#define ML_CNXK_MODEL_MAX_LAYERS TVMDP_MODEL_LAYERS_MAX
+#define ML_CNXK_MODEL_MAX_LAYERS 128
#else
#define ML_CNXK_MODEL_MAX_LAYERS 1
#endif
@@ -41,7 +41,7 @@ struct cnxk_ml_io {
/* Number of dimensions in shape */
uint32_t nb_dims;
- /* Shape of input */
+ /* Shape */
uint32_t shape[ML_CNXK_MODEL_MAX_DIMS];
/* Number of elements */
@@ -58,6 +58,20 @@ struct cnxk_ml_io {
/* Zero point */
int64_t zero_point;
+
+#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
+ /* Shape - int64_t */
+ int64_t shape_i64[ML_CNXK_MODEL_MAX_DIMS];
+
+ /* Data type */
+ DLDataType datatype;
+
+ /* Model data type */
+ DLDataType model_datatype;
+
+ /* Device */
+ DLDevice device;
+#endif
};
/* Model / Layer IO structure */
diff --git a/drivers/ml/cnxk/cnxk_ml_ops.c b/drivers/ml/cnxk/cnxk_ml_ops.c
index 9958945670a..938982c7556 100644
--- a/drivers/ml/cnxk/cnxk_ml_ops.c
+++ b/drivers/ml/cnxk/cnxk_ml_ops.c
@@ -634,10 +634,6 @@ cnxk_ml_dev_configure(struct rte_ml_dev *dev, const struct rte_ml_dev_config *co
}
}
- ret = mvtvm_ml_dev_configure(cnxk_mldev, conf);
- if (ret != 0)
- goto error;
-
/* Set device capabilities */
if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI)
cnxk_mldev->max_nb_layers =
@@ -705,9 +701,6 @@ cnxk_ml_dev_close(struct rte_ml_dev *dev)
/* Un-initialize xstats */
cnxk_ml_xstats_uninit(cnxk_mldev);
- if (mvtvm_ml_dev_close(cnxk_mldev) != 0)
- plt_err("Failed to close MVTVM ML Device");
-
if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_PCI) {
if (cn10k_ml_dev_close(cnxk_mldev) != 0)
plt_err("Failed to close CN10K ML Device");
@@ -1234,7 +1227,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
model->layer[layer_id].glow.ocm_map.scratch_pages);
#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
} else {
- for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) {
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) {
total_wb_pages = total_wb_pages +
model->layer[layer_id].glow.ocm_map.wb_pages;
@@ -1256,8 +1249,7 @@ cnxk_ml_model_load(struct rte_ml_dev *dev, struct rte_ml_model_params *params, u
model->layer[layer_id].glow.ocm_map.scratch_pages);
#ifdef RTE_MLDEV_CNXK_ENABLE_MVTVM
} else {
- for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers;
- layer_id++) {
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (model->layer[layer_id].type == ML_CNXK_LAYER_TYPE_MRVL) {
plt_ml_dbg(
"layer_id = %u: wb_pages = %u, scratch_pages = %u",
diff --git a/drivers/ml/cnxk/meson.build b/drivers/ml/cnxk/meson.build
index ef7e21d7476..5f078bd4fd7 100644
--- a/drivers/ml/cnxk/meson.build
+++ b/drivers/ml/cnxk/meson.build
@@ -19,30 +19,24 @@ if not jansson_dep.found()
enable_mvtvm = false
endif
-dlpack_dep = dependency('dlpack', method: 'cmake', required: false, cmake_args: 'CONFIG')
+dlpack_dep = dependency('dlpack', method: 'cmake', required: false)
if not dlpack_dep.found()
message('drivers/ml/cnxk: dlpack not found')
enable_mvtvm = false
endif
-dmlc_dep = dependency('dmlc', method: 'cmake', required: false, cmake_args: 'CONFIG')
+dmlc_dep = dependency('dmlc', method: 'cmake', required: false)
if not dmlc_dep.found()
message('drivers/ml/cnxk: dmlc not found')
enable_mvtvm = false
endif
-tvm_dep = dependency('tvm', method: 'cmake', required: false, cmake_args: 'CONFIG', modules : ['tvm::tvm_runtime'])
+tvm_dep = dependency('tvm', method: 'cmake', required: false, modules : ['tvm::tvm_runtime'])
if not tvm_dep.found()
message('drivers/ml/cnxk: tvm_runtime not found')
enable_mvtvm = false
endif
-tvmdp_dep = dependency('tvmdp', method: 'pkg-config', required: false)
-if not tvmdp_dep.found()
- message('drivers/ml/cnxk: tvmdp not found')
- enable_mvtvm = false
-endif
-
sources = files(
'cn10k_ml_dev.c',
'cn10k_ml_ops.c',
@@ -68,10 +62,10 @@ sources += files(
)
ext_deps += jansson_dep
+ext_deps += libarchive
ext_deps += dlpack_dep
ext_deps += dmlc_dep
ext_deps += tvm_dep
-ext_deps += tvmdp_dep
stdcpp_dep = cc.find_library('stdc++', required: true)
if not cc.links(min_c_code, dependencies: stdcpp_dep)
error('broken dependency, "libstdc++"')
diff --git a/drivers/ml/cnxk/mvtvm_ml_dev.h b/drivers/ml/cnxk/mvtvm_ml_dev.h
index 6922c193372..05e30f094cd 100644
--- a/drivers/ml/cnxk/mvtvm_ml_dev.h
+++ b/drivers/ml/cnxk/mvtvm_ml_dev.h
@@ -19,9 +19,6 @@ extern struct rte_ml_dev_ops cnxk_ml_ops;
/* Maximum number of descriptors per queue-pair */
#define ML_MVTVM_MAX_DESC_PER_QP 1024
-/* Maximum number of inputs / outputs per model */
-#define ML_MVTVM_MAX_INPUT_OUTPUT 32
-
/* Maximum number of segments for IO data */
#define ML_MVTVM_MAX_SEGMENTS 1
diff --git a/drivers/ml/cnxk/mvtvm_ml_model.c b/drivers/ml/cnxk/mvtvm_ml_model.c
index 4c7aa906da0..e1946607629 100644
--- a/drivers/ml/cnxk/mvtvm_ml_model.c
+++ b/drivers/ml/cnxk/mvtvm_ml_model.c
@@ -2,6 +2,12 @@
* Copyright (c) 2023 Marvell.
*/
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#include <archive.h>
#include <archive_entry.h>
@@ -23,6 +29,7 @@ enum cnxk_ml_model_type
mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
{
bool object_found[ML_MVTVM_MODEL_OBJECT_MAX] = {false, false, false};
+ enum cnxk_ml_model_type model_type;
struct archive_entry *entry;
struct archive *a;
uint8_t i;
@@ -33,9 +40,10 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
+ model_type = ML_CNXK_MODEL_TYPE_UNKNOWN;
ret = archive_read_open_memory(a, params->addr, params->size);
if (ret != ARCHIVE_OK)
- return ML_CNXK_MODEL_TYPE_UNKNOWN;
+ goto cleanup;
/* Parse buffer for available objects */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
@@ -51,11 +59,18 @@ mvtvm_ml_model_type_get(struct rte_ml_model_params *params)
for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
if (!object_found[i]) {
plt_err("Object %s not found in archive!", mvtvm_object_list[i]);
- return ML_CNXK_MODEL_TYPE_INVALID;
+ model_type = ML_CNXK_MODEL_TYPE_INVALID;
+ goto cleanup;
}
}
- return ML_CNXK_MODEL_TYPE_TVM;
+ model_type = ML_CNXK_MODEL_TYPE_TVM;
+
+cleanup:
+ archive_read_close(a);
+ archive_read_free(a);
+
+ return model_type;
}
int
@@ -67,14 +82,18 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
uint8_t i;
int ret;
+ memset(object, 0, ML_MVTVM_MODEL_OBJECT_MAX * sizeof(*object));
+
/* Open archive */
a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
ret = archive_read_open_memory(a, params->addr, params->size);
- if (ret != ARCHIVE_OK)
- return archive_errno(a);
+ if (ret != ARCHIVE_OK) {
+ ret = archive_errno(a);
+ goto cleanup;
+ }
/* Read archive */
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
@@ -84,11 +103,16 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
memcpy(object[i].name, mvtvm_object_list[i], RTE_ML_STR_MAX);
object[i].size = archive_entry_size(entry);
object[i].buffer = rte_malloc(NULL, object[i].size, 0);
+ if (object[i].buffer == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
if (archive_read_data(a, object[i].buffer, object[i].size) !=
object[i].size) {
plt_err("Failed to read object from model archive: %s",
object[i].name);
+ ret = -EINVAL;
goto error;
}
object_found[i] = true;
@@ -101,17 +125,24 @@ mvtvm_ml_model_blob_parse(struct rte_ml_model_params *params, struct mvtvm_ml_mo
for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
if (!object_found[i]) {
plt_err("Object %s not found in archive!", mvtvm_object_list[i]);
+ ret = -EINVAL;
goto error;
}
}
- return 0;
+ ret = 0;
+ goto cleanup;
error:
for (i = 0; i < ML_MVTVM_MODEL_OBJECT_MAX; i++) {
- rte_free(object[i].buffer);
+ if (object[i].buffer != NULL)
+ rte_free(object[i].buffer);
}
- return -EINVAL;
+cleanup:
+ archive_read_close(a);
+ archive_read_free(a);
+
+ return ret;
}
int
@@ -119,12 +150,12 @@ mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
{
uint16_t i;
- for (i = 0; i < model->mvtvm.metadata.model.nb_layers; i++) {
+ for (i = 0; i < model->nb_layers; i++) {
if (strcmp(model->layer[i].name, layer_name) == 0)
break;
}
- if (i == model->mvtvm.metadata.model.nb_layers) {
+ if (i == model->nb_layers) {
plt_err("Invalid layer name: %s", layer_name);
return -EINVAL;
}
@@ -139,6 +170,506 @@ mvtvm_ml_model_get_layer_id(struct cnxk_ml_model *model, const char *layer_name,
return 0;
}
+static void
+mvtvm_ml_param_names_free(struct mvtvm_ml_param_names *param_names)
+{
+ size_t i;
+
+ for (i = 0; i < param_names->count; i++)
+ free(param_names->name[i]);
+
+ free(param_names->name);
+ param_names->name = NULL;
+ param_names->count = 0;
+}
+
+static int
+mvtvm_ml_blob_read_u64(const uint8_t *blob, size_t blob_size, size_t *offset, uint64_t *value)
+{
+ if (*offset + sizeof(*value) > blob_size)
+ return -EINVAL;
+
+ memcpy(value, blob + *offset, sizeof(*value));
+ *offset += sizeof(*value);
+
+ return 0;
+}
+
+static int
+mvtvm_ml_param_names_parse(const uint8_t *blob, size_t blob_size,
+ struct mvtvm_ml_param_names *param_names)
+{
+ uint64_t magic = 0;
+ uint64_t reserved = 0;
+ uint64_t count = 0;
+ size_t offset = 0;
+ int ret;
+ size_t i;
+
+ memset(param_names, 0, sizeof(*param_names));
+
+ ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &magic);
+ if (ret != 0)
+ return ret;
+
+ if (magic != TVM_NDARRAY_LIST_MAGIC)
+ return -EINVAL;
+
+ ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &reserved);
+ if (ret != 0)
+ return ret;
+
+ ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &count);
+ if (ret != 0)
+ return ret;
+
+ if (count > SIZE_MAX / sizeof(*param_names->name))
+ return -EINVAL;
+
+ param_names->name = calloc(count, sizeof(*param_names->name));
+ if (count != 0 && param_names->name == NULL)
+ return -ENOMEM;
+
+ param_names->count = count;
+ for (i = 0; i < count; i++) {
+ uint64_t name_len = 0;
+
+ ret = mvtvm_ml_blob_read_u64(blob, blob_size, &offset, &name_len);
+ if (ret != 0)
+ goto error;
+
+ if (name_len == SIZE_MAX) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (offset + name_len > blob_size) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ param_names->name[i] = calloc(name_len + 1, 1);
+ if (param_names->name[i] == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(param_names->name[i], blob + offset, name_len);
+ offset += name_len;
+ }
+
+ return 0;
+
+error:
+ mvtvm_ml_param_names_free(param_names);
+ return ret;
+}
+
+static int
+mvtvm_ml_dtype_parse(const char *dtype_str, DLDataType *dtype)
+{
+ const char *lanes_str;
+ char base[32] = {0};
+ long bits;
+ long lanes = 1;
+
+ if (dtype_str == NULL || dtype == NULL)
+ return -EINVAL;
+
+ lanes_str = strchr(dtype_str, 'x');
+ if (lanes_str != NULL) {
+ size_t base_len = lanes_str - dtype_str;
+
+ if (base_len >= sizeof(base))
+ return -EINVAL;
+ memcpy(base, dtype_str, base_len);
+ lanes = strtol(lanes_str + 1, NULL, 10);
+ if (lanes <= 0 || lanes > UINT16_MAX)
+ return -EINVAL;
+ } else {
+ snprintf(base, sizeof(base), "%s", dtype_str);
+ }
+
+ memset(dtype, 0, sizeof(*dtype));
+ dtype->lanes = (uint16_t)lanes;
+
+ if (strncmp(base, "int", 3) == 0) {
+ bits = strtol(base + 3, NULL, 10);
+ dtype->code = kDLInt;
+ } else if (strncmp(base, "uint", 4) == 0) {
+ bits = strtol(base + 4, NULL, 10);
+ dtype->code = kDLUInt;
+ } else if (strncmp(base, "float", 5) == 0) {
+ bits = strtol(base + 5, NULL, 10);
+ dtype->code = kDLFloat;
+ } else if (strncmp(base, "bfloat", 6) == 0) {
+ bits = strtol(base + 6, NULL, 10);
+ dtype->code = kDLBfloat;
+ } else if (strcmp(base, "bool") == 0) {
+ bits = 1;
+ dtype->code = kDLUInt;
+ } else {
+ return -EINVAL;
+ }
+
+ if (bits <= 0 || bits > UINT8_MAX)
+ return -EINVAL;
+
+ dtype->bits = (uint8_t)bits;
+
+ return 0;
+}
+
+static int
+mvtvm_ml_model_io_set(struct cnxk_ml_io *io, const char *name, json_t *shape, const char *dtype_str,
+ DLDevice device)
+{
+ size_t i;
+ int ret;
+
+ memset(io, 0, sizeof(*io));
+ if (name != NULL)
+ snprintf(io->name, sizeof(io->name), "%s", name);
+
+ if (!json_is_array(shape))
+ return -EINVAL;
+
+ io->nb_dims = json_array_size(shape);
+ if (io->nb_dims > ML_CNXK_MODEL_MAX_DIMS)
+ return -ENOTSUP;
+
+ for (i = 0; i < (size_t)io->nb_dims; i++) {
+ json_t *dim = json_array_get(shape, i);
+
+ if (!json_is_integer(dim))
+ return -EINVAL;
+ io->shape_i64[i] = json_integer_value(dim);
+ }
+
+ ret = mvtvm_ml_dtype_parse(dtype_str, &io->datatype);
+ if (ret != 0)
+ return ret;
+
+ io->model_datatype = io->datatype;
+ io->scale = 1.0f;
+ io->device = device;
+
+ return 0;
+}
+
+static int
+mvtvm_ml_json_graph_get_arrays(json_t *json_parsed, json_t **nodes, json_t **arg_nodes,
+ json_t **heads, json_t **node_row_ptr, json_t **shape_values,
+ json_t **dtype_values)
+{
+ json_t *attrs;
+ json_t *shape_attr;
+ json_t *dtype_attr;
+
+ *nodes = json_object_get(json_parsed, "nodes");
+ *arg_nodes = json_object_get(json_parsed, "arg_nodes");
+ *heads = json_object_get(json_parsed, "heads");
+ *node_row_ptr = json_object_get(json_parsed, "node_row_ptr");
+ attrs = json_object_get(json_parsed, "attrs");
+
+ if (!json_is_array(*nodes) || !json_is_array(*arg_nodes) || !json_is_array(*heads) ||
+ !json_is_array(*node_row_ptr) || !json_is_object(attrs))
+ return -EINVAL;
+
+ if (json_array_size(*node_row_ptr) != json_array_size(*nodes) + 1)
+ return -EINVAL;
+
+ shape_attr = json_object_get(attrs, "shape");
+ dtype_attr = json_object_get(attrs, "dltype");
+ if (!json_is_array(shape_attr) || json_array_size(shape_attr) < 2 ||
+ !json_is_array(dtype_attr) || json_array_size(dtype_attr) < 2)
+ return -EINVAL;
+
+ *shape_values = json_array_get(shape_attr, 1);
+ *dtype_values = json_array_get(dtype_attr, 1);
+
+ if (!json_is_array(*shape_values) || !json_is_array(*dtype_values))
+ return -EINVAL;
+
+ return 0;
+}
+
+int
+mvtvm_ml_model_json_parse(struct cnxk_ml_model *model)
+{
+ struct mvtvm_ml_param_names param_names;
+ json_error_t json_error;
+ json_t *json_parsed;
+ json_t *json_nodes;
+ json_t *json_arg_nodes;
+ json_t *json_heads;
+ json_t *json_node_row_ptr;
+ json_t *json_shape_values;
+ json_t *json_dtype_values;
+ uint16_t nb_mrvl_layers;
+ uint16_t nb_llvm_layers;
+ DLDevice device;
+ int ret;
+ size_t i;
+ size_t j;
+
+ /* Parse param names from params buffer */
+ ret = mvtvm_ml_param_names_parse(model->mvtvm.params.buffer, model->mvtvm.params.size,
+ ¶m_names);
+ if (ret != 0)
+ return ret;
+
+ /* Load JSON graph (single load for both stages) */
+ json_parsed = json_loadb((const char *)model->mvtvm.json.buffer, model->mvtvm.json.size, 0,
+ &json_error);
+ if (json_parsed == NULL) {
+ mvtvm_ml_param_names_free(¶m_names);
+ plt_err("TVM runtime: Failed to parse JSON graph, model_id = %u", model->model_id);
+ return -EINVAL;
+ }
+
+ /* Parse nodes to extract layer info */
+ json_nodes = json_object_get(json_parsed, "nodes");
+ if (!json_is_array(json_nodes)) {
+ ret = -EINVAL;
+ plt_err("TVM runtime: Failed to parse JSON nodes, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ model->nb_layers = 0;
+ nb_mrvl_layers = 0;
+ nb_llvm_layers = 0;
+ for (i = 0; i < json_array_size(json_nodes); i++) {
+ json_t *node = json_array_get(json_nodes, i);
+ json_t *op = json_object_get(node, "op");
+ json_t *name;
+ json_t *attrs;
+ json_t *compiler;
+
+ if (!json_is_string(op) || strcmp(json_string_value(op), "tvm_op") != 0)
+ continue;
+
+ if (model->nb_layers >= ML_CNXK_MODEL_MAX_LAYERS) {
+ ret = -ENOTSUP;
+ plt_err("TVM runtime: Number of layers exceeds maximum (%u), model_id = %u, error = %d",
+ ML_CNXK_MODEL_MAX_LAYERS, model->model_id, ret);
+ goto error;
+ }
+
+ name = json_object_get(node, "name");
+ if (!json_is_string(name)) {
+ ret = -EINVAL;
+ plt_err("TVM runtime: Failed to parse JSON node name, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ if (json_string_value(name) != NULL)
+ snprintf(model->layer[model->nb_layers].name,
+ sizeof(model->layer[model->nb_layers].name), "%s",
+ json_string_value(name));
+ else
+ snprintf(model->layer[model->nb_layers].name,
+ sizeof(model->layer[model->nb_layers].name), "tvm_layer_%u",
+ model->nb_layers);
+
+ attrs = json_object_get(node, "attrs");
+ compiler = json_is_object(attrs) ? json_object_get(attrs, "Compiler") : NULL;
+ if (json_is_string(compiler)) {
+ if (strcmp(json_string_value(compiler), "mrvl") == 0 ||
+ strcmp(json_string_value(compiler), "MRVL") == 0) {
+ model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_MRVL;
+ nb_mrvl_layers++;
+ } else {
+ model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_UNKNOWN;
+ }
+ } else {
+ model->layer[model->nb_layers].type = ML_CNXK_LAYER_TYPE_LLVM;
+ nb_llvm_layers++;
+ }
+ model->nb_layers++;
+ }
+
+ /* Set model fields */
+ snprintf(model->name, sizeof(model->name), "tvm_model_%u", model->model_id);
+ model->batch_size = 1;
+
+ /* Validate layer counts */
+ if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 0)) {
+ plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u", nb_llvm_layers,
+ nb_mrvl_layers);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (nb_llvm_layers + nb_mrvl_layers != model->nb_layers) {
+ plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u, nb_layers = %u",
+ nb_llvm_layers, nb_mrvl_layers, model->nb_layers);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Set model subtype */
+ if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 1))
+ model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_MRVL;
+ else if ((nb_llvm_layers > 0) && (nb_mrvl_layers == 0))
+ model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_LLVM;
+ else
+ model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_HYBRID;
+
+ /* Parse I/O info from the same JSON graph */
+ device.device_type = kDLCPU;
+ device.device_id = 0;
+
+ ret = mvtvm_ml_json_graph_get_arrays(json_parsed, &json_nodes, &json_arg_nodes, &json_heads,
+ &json_node_row_ptr, &json_shape_values,
+ &json_dtype_values);
+ if (ret == 0) {
+ model->mvtvm.info.nb_inputs = 0;
+ model->mvtvm.info.nb_outputs = 0;
+
+ for (i = 0; i < json_array_size(json_arg_nodes); i++) {
+ json_t *arg_node_idx = json_array_get(json_arg_nodes, i);
+ json_t *node;
+ json_t *shape;
+ json_t *dtype;
+ json_t *name;
+ json_int_t node_id;
+
+ if (!json_is_integer(arg_node_idx)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ node_id = json_integer_value(arg_node_idx);
+ node = json_array_get(json_nodes, node_id);
+ shape = json_array_get(json_shape_values, node_id);
+ dtype = json_array_get(json_dtype_values, node_id);
+ name = json_object_get(node, "name");
+ if (!json_is_object(node) || !json_is_array(shape) ||
+ !json_is_string(dtype) || !json_is_string(name)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ for (j = 0; j < param_names.count; j++) {
+ if (strcmp(param_names.name[j], json_string_value(name)) == 0)
+ break;
+ }
+
+ if (j < param_names.count)
+ continue;
+
+ if (model->mvtvm.info.nb_inputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
+ ret = -ENOTSUP;
+ break;
+ }
+
+ ret = mvtvm_ml_model_io_set(
+ &model->mvtvm.info.input[model->mvtvm.info.nb_inputs],
+ json_string_value(name), shape, json_string_value(dtype), device);
+ if (ret != 0)
+ break;
+
+ model->mvtvm.info.nb_inputs++;
+ }
+
+ for (i = 0; ret == 0 && i < json_array_size(json_heads); i++) {
+ json_t *head = json_array_get(json_heads, i);
+ json_t *node;
+ json_t *shape;
+ json_t *dtype;
+ json_t *name;
+ json_t *node_id_json;
+ json_t *output_idx_json;
+ json_t *entry_base_json;
+ json_t *entry_limit_json;
+ json_int_t node_id;
+ json_int_t output_idx;
+ json_int_t entry_base;
+ json_int_t entry_limit;
+ size_t entry_id;
+
+ if (!json_is_array(head) || json_array_size(head) < 2) {
+ ret = -EINVAL;
+ break;
+ }
+
+ node_id_json = json_array_get(head, 0);
+ output_idx_json = json_array_get(head, 1);
+ if (!json_is_integer(node_id_json) || !json_is_integer(output_idx_json)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ node_id = json_integer_value(node_id_json);
+ output_idx = json_integer_value(output_idx_json);
+ if (node_id < 0 || output_idx < 0) {
+ ret = -EINVAL;
+ break;
+ }
+
+ node = json_array_get(json_nodes, (size_t)node_id);
+ entry_base_json = json_array_get(json_node_row_ptr, (size_t)node_id);
+ entry_limit_json = json_array_get(json_node_row_ptr, (size_t)node_id + 1);
+ if (!json_is_object(node) || !json_is_integer(entry_base_json) ||
+ !json_is_integer(entry_limit_json)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ entry_base = json_integer_value(entry_base_json);
+ entry_limit = json_integer_value(entry_limit_json);
+ if (entry_base < 0 || entry_limit < entry_base) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (output_idx >= (entry_limit - entry_base)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ entry_id = (size_t)entry_base + (size_t)output_idx;
+ shape = json_array_get(json_shape_values, entry_id);
+ dtype = json_array_get(json_dtype_values, entry_id);
+ name = json_object_get(node, "name");
+ if (!json_is_array(shape) || !json_is_string(dtype) ||
+ !json_is_string(name)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (model->mvtvm.info.nb_outputs >= ML_CNXK_MODEL_MAX_INPUT_OUTPUT) {
+ ret = -ENOTSUP;
+ break;
+ }
+
+ ret = mvtvm_ml_model_io_set(
+ &model->mvtvm.info.output[model->mvtvm.info.nb_outputs],
+ json_string_value(name), shape, json_string_value(dtype), device);
+ if (ret != 0)
+ break;
+
+ model->mvtvm.info.nb_outputs++;
+ }
+ }
+
+ if (ret != 0)
+ plt_err("TVM runtime: Failed to get metadata, model_id = %u, error = %d",
+ model->model_id, ret);
+
+ json_decref(json_parsed);
+ mvtvm_ml_param_names_free(¶m_names);
+ return ret;
+
+error:
+ json_decref(json_parsed);
+ mvtvm_ml_param_names_free(¶m_names);
+ return ret;
+}
+
static enum rte_ml_io_type
mvtvm_ml_io_type_map(DLDataType dltype)
{
@@ -185,32 +716,27 @@ mvtvm_ml_io_type_map(DLDataType dltype)
void
mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
{
- struct tvmdp_model_metadata *metadata;
int32_t i;
- int32_t j;
+ uint32_t j;
if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL)
goto tvm_mrvl_model;
- metadata = &model->mvtvm.metadata;
-
/* Inputs, set for layer_id = 0 */
- model->mvtvm.info.nb_inputs = metadata->model.num_input;
model->mvtvm.info.total_input_sz_d = 0;
model->mvtvm.info.total_input_sz_q = 0;
- for (i = 0; i < metadata->model.num_input; i++) {
- rte_strscpy(model->mvtvm.info.input[i].name, metadata->input[i].name,
- TVMDP_NAME_STRLEN);
+ for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
model->mvtvm.info.input[i].dtype =
- mvtvm_ml_io_type_map(metadata->input[i].datatype);
+ mvtvm_ml_io_type_map(model->mvtvm.info.input[i].datatype);
model->mvtvm.info.input[i].qtype =
- mvtvm_ml_io_type_map(metadata->input[i].model_datatype);
- model->mvtvm.info.input[i].nb_dims = metadata->input[i].ndim;
+ mvtvm_ml_io_type_map(model->mvtvm.info.input[i].model_datatype);
model->mvtvm.info.input[i].nb_elements = 1;
- for (j = 0; j < metadata->input[i].ndim; j++) {
- model->mvtvm.info.input[i].shape[j] = metadata->input[i].shape[j];
- model->mvtvm.info.input[i].nb_elements *= metadata->input[i].shape[j];
+ for (j = 0; j < model->mvtvm.info.input[i].nb_dims; j++) {
+ model->mvtvm.info.input[i].shape[j] =
+ PLT_U32_CAST(model->mvtvm.info.input[i].shape_i64[j]);
+ model->mvtvm.info.input[i].nb_elements *=
+ model->mvtvm.info.input[i].shape[j];
}
model->mvtvm.info.input[i].sz_d =
@@ -219,15 +745,14 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
model->mvtvm.info.input[i].sz_q =
model->mvtvm.info.input[i].nb_elements *
rte_ml_io_type_size_get(model->mvtvm.info.input[i].qtype);
- model->mvtvm.info.input[i].scale = metadata->input[i].scale;
model->mvtvm.info.total_input_sz_d += model->mvtvm.info.input[i].sz_d;
model->mvtvm.info.total_input_sz_q += model->mvtvm.info.input[i].sz_q;
- model->mvtvm.input_tensor[i].device = metadata->input[i].device;
- model->mvtvm.input_tensor[i].ndim = metadata->input[i].ndim;
- model->mvtvm.input_tensor[i].dtype = metadata->input[i].datatype;
- model->mvtvm.input_tensor[i].shape = metadata->input[i].shape;
+ model->mvtvm.input_tensor[i].device = model->mvtvm.info.input[i].device;
+ model->mvtvm.input_tensor[i].ndim = model->mvtvm.info.input[i].nb_dims;
+ model->mvtvm.input_tensor[i].dtype = model->mvtvm.info.input[i].datatype;
+ model->mvtvm.input_tensor[i].shape = model->mvtvm.info.input[i].shape_i64;
model->mvtvm.input_tensor[i].strides = NULL;
model->mvtvm.input_tensor[i].byte_offset = 0;
@@ -236,22 +761,20 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
}
/* Outputs, set for nb_layers - 1 */
- model->mvtvm.info.nb_outputs = metadata->model.num_output;
model->mvtvm.info.total_output_sz_d = 0;
model->mvtvm.info.total_output_sz_q = 0;
- for (i = 0; i < metadata->model.num_output; i++) {
- rte_strscpy(model->mvtvm.info.output[i].name, metadata->output[i].name,
- TVMDP_NAME_STRLEN);
+ for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
model->mvtvm.info.output[i].dtype =
- mvtvm_ml_io_type_map(metadata->output[i].datatype);
+ mvtvm_ml_io_type_map(model->mvtvm.info.output[i].datatype);
model->mvtvm.info.output[i].qtype =
- mvtvm_ml_io_type_map(metadata->output[i].model_datatype);
- model->mvtvm.info.output[i].nb_dims = metadata->output[i].ndim;
+ mvtvm_ml_io_type_map(model->mvtvm.info.output[i].model_datatype);
model->mvtvm.info.output[i].nb_elements = 1;
- for (j = 0; j < metadata->output[i].ndim; j++) {
- model->mvtvm.info.output[i].shape[j] = metadata->output[i].shape[j];
- model->mvtvm.info.output[i].nb_elements *= metadata->output[i].shape[j];
+ for (j = 0; j < model->mvtvm.info.output[i].nb_dims; j++) {
+ model->mvtvm.info.output[i].shape[j] =
+ PLT_U32_CAST(model->mvtvm.info.output[i].shape_i64[j]);
+ model->mvtvm.info.output[i].nb_elements *=
+ model->mvtvm.info.output[i].shape[j];
}
model->mvtvm.info.output[i].sz_d =
@@ -260,15 +783,14 @@ mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model)
model->mvtvm.info.output[i].sz_q =
model->mvtvm.info.output[i].nb_elements *
rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype);
- model->mvtvm.info.output[i].scale = metadata->output[i].scale;
model->mvtvm.info.total_output_sz_d += model->mvtvm.info.output[i].sz_d;
model->mvtvm.info.total_output_sz_q += model->mvtvm.info.output[i].sz_q;
- model->mvtvm.output_tensor[i].device = metadata->output[i].device;
- model->mvtvm.output_tensor[i].ndim = metadata->output[i].ndim;
- model->mvtvm.output_tensor[i].dtype = metadata->output[i].datatype;
- model->mvtvm.output_tensor[i].shape = metadata->output[i].shape;
+ model->mvtvm.output_tensor[i].device = model->mvtvm.info.output[i].device;
+ model->mvtvm.output_tensor[i].ndim = model->mvtvm.info.output[i].nb_dims;
+ model->mvtvm.output_tensor[i].dtype = model->mvtvm.info.output[i].datatype;
+ model->mvtvm.output_tensor[i].shape = model->mvtvm.info.output[i].shape_i64;
model->mvtvm.output_tensor[i].strides = NULL;
model->mvtvm.output_tensor[i].byte_offset = 0;
@@ -293,7 +815,6 @@ mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id)
void
mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model)
{
- struct tvmdp_model_metadata *metadata;
struct rte_ml_model_info *info;
struct rte_ml_io_info *output;
struct rte_ml_io_info *input;
@@ -309,26 +830,23 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
if (model->subtype == ML_CNXK_MODEL_SUBTYPE_TVM_MRVL)
goto tvm_mrvl_model;
- metadata = &model->mvtvm.metadata;
- rte_memcpy(info->name, metadata->model.name, TVMDP_NAME_STRLEN);
- snprintf(info->version, RTE_ML_STR_MAX, "%u.%u.%u.%u", metadata->model.version[0],
- metadata->model.version[1], metadata->model.version[2],
- metadata->model.version[3]);
+ rte_memcpy(info->name, model->name, RTE_ML_STR_MAX);
+ snprintf(info->version, RTE_ML_STR_MAX, "%u.%u.%u.%u", 0, 0, 0, 0);
info->model_id = model->model_id;
info->device_id = cnxk_mldev->mldev->data->dev_id;
info->io_layout = RTE_ML_IO_LAYOUT_SPLIT;
info->min_batches = model->batch_size;
info->max_batches = model->batch_size;
- info->nb_inputs = metadata->model.num_input;
+ info->nb_inputs = model->mvtvm.info.nb_inputs;
info->input_info = input;
- info->nb_outputs = metadata->model.num_output;
+ info->nb_outputs = model->mvtvm.info.nb_outputs;
info->output_info = output;
info->wb_size = 0;
/* Set input info */
for (i = 0; i < info->nb_inputs; i++) {
- rte_memcpy(input[i].name, metadata->input[i].name, MRVL_ML_INPUT_NAME_LEN);
- input[i].nb_dims = metadata->input[i].ndim;
+ rte_memcpy(input[i].name, model->mvtvm.info.input[i].name, MRVL_ML_INPUT_NAME_LEN);
+ input[i].nb_dims = model->mvtvm.info.input[i].nb_dims;
input[i].shape = &model->mvtvm.info.input[i].shape[0];
input[i].type = model->mvtvm.info.input[i].qtype;
input[i].nb_elements = model->mvtvm.info.input[i].nb_elements;
@@ -340,15 +858,16 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
/* Set output info */
for (i = 0; i < info->nb_outputs; i++) {
- rte_memcpy(output[i].name, metadata->output[i].name, MRVL_ML_OUTPUT_NAME_LEN);
- output[i].nb_dims = metadata->output[i].ndim;
+ rte_memcpy(output[i].name, model->mvtvm.info.output[i].name,
+ MRVL_ML_OUTPUT_NAME_LEN);
+ output[i].nb_dims = model->mvtvm.info.output[i].nb_dims;
output[i].shape = &model->mvtvm.info.output[i].shape[0];
output[i].type = model->mvtvm.info.output[i].qtype;
output[i].nb_elements = model->mvtvm.info.output[i].nb_elements;
output[i].size = model->mvtvm.info.output[i].nb_elements *
rte_ml_io_type_size_get(model->mvtvm.info.output[i].qtype);
- input[i].scale = model->mvtvm.info.output[i].scale;
- input[i].zero_point = 0;
+ output[i].scale = model->mvtvm.info.output[i].scale;
+ output[i].zero_point = 0;
}
return;
@@ -357,8 +876,7 @@ mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mo
cn10k_ml_model_info_set(cnxk_mldev, model, &model->mvtvm.info,
&model->layer[0].glow.metadata);
- metadata = &model->mvtvm.metadata;
- strlcpy(info->name, metadata->model.name, TVMDP_NAME_STRLEN);
+ strlcpy(info->name, model->name, RTE_ML_STR_MAX);
info->io_layout = RTE_ML_IO_LAYOUT_PACKED;
}
diff --git a/drivers/ml/cnxk/mvtvm_ml_model.h b/drivers/ml/cnxk/mvtvm_ml_model.h
index 7ffce380945..1151b0a39ed 100644
--- a/drivers/ml/cnxk/mvtvm_ml_model.h
+++ b/drivers/ml/cnxk/mvtvm_ml_model.h
@@ -5,7 +5,21 @@
#ifndef _MVTVM_ML_MODEL_H_
#define _MVTVM_ML_MODEL_H_
-#include <tvmdp.h>
+#include <dlpack/dlpack.h>
+#include <jansson.h>
+#include <rte_common.h>
+
+#if defined(RTE_CC_GCC) || defined(RTE_CC_CLANG)
+__rte_diagnostic_push
+RTE_PRAGMA(GCC diagnostic ignored "-Wstrict-prototypes")
+#include <tvm/runtime/c_runtime_api.h>
+__rte_diagnostic_pop
+#else
+#include <tvm/runtime/c_runtime_api.h>
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
#include <rte_mldev.h>
@@ -18,19 +32,56 @@ struct cnxk_ml_layer;
/* Maximum number of objects per model */
#define ML_MVTVM_MODEL_OBJECT_MAX 3
-/* Objects list */
-extern char mvtvm_object_list[ML_MVTVM_MODEL_OBJECT_MAX][RTE_ML_STR_MAX];
+/* Magic number for TVM parameter blobs. */
+#define TVM_NDARRAY_LIST_MAGIC 0xF7E58D4F05049CB7ULL
-/* Model object structure */
+/* TVM parameter names structure */
+struct mvtvm_ml_param_names {
+ char **name;
+ size_t count;
+};
+
+/* TVM object / artifact info structure */
struct mvtvm_ml_model_object {
/* Name */
char name[RTE_ML_STR_MAX];
- /* Temporary buffer */
+ /* Buffer address */
uint8_t *buffer;
/* Buffer size */
int64_t size;
+
+ /* Offset */
+ uint32_t offset;
+};
+
+/* Glow model callback functions */
+typedef int (*tvmrt_glow_layer_load_cb)(void *device, uint16_t model_id, const char *layer_name,
+ uint8_t *buffer, size_t size, uint16_t *index);
+typedef int (*tvmrt_glow_layer_unload_cb)(void *device, uint16_t model_id, const char *layer_name);
+typedef int (*tvmrt_io_alloc_cb)(void *device, uint16_t model_id, const char *layer_name,
+ uint64_t **input_qbuffer, uint64_t **output_qbuffer);
+typedef int (*tvmrt_io_free_cb)(void *device, uint16_t model_id, const char *layer_name);
+typedef int (*tvmrt_malloc_cb)(const char *name, size_t size, uint32_t align, void **addr);
+typedef int (*tvmrt_free_cb)(const char *name);
+typedef int (*tvmrt_quantize_cb)(void *device, uint16_t model_id, const char *layer_name,
+ const DLTensor **deq_tensor, void *qbuffer);
+typedef int (*tvmrt_dequantize_cb)(void *device, uint16_t model_id, const char *layer_name,
+ void *qbuffer, const DLTensor **deq_tensor);
+typedef int (*tvmrt_inference_cb)(void *device, uint16_t index, void *input, void *output,
+ uint16_t nb_batches);
+
+struct tvmrt_glow_callback {
+ tvmrt_glow_layer_load_cb tvmrt_glow_layer_load;
+ tvmrt_glow_layer_unload_cb tvmrt_glow_layer_unload;
+ tvmrt_io_alloc_cb tvmrt_io_alloc;
+ tvmrt_io_free_cb tvmrt_io_free;
+ tvmrt_malloc_cb tvmrt_malloc;
+ tvmrt_free_cb tvmrt_free;
+ tvmrt_quantize_cb tvmrt_quantize;
+ tvmrt_dequantize_cb tvmrt_dequantize;
+ tvmrt_inference_cb tvmrt_inference;
};
/* Model fast-path stats */
@@ -55,15 +106,26 @@ struct mvtvm_ml_model_xstats {
};
struct mvtvm_ml_model_data {
- /* Model metadata */
- struct tvmdp_model_metadata metadata;
-
/* Model objects */
- struct tvmdp_model_object object;
+ struct mvtvm_ml_model_object so;
+ struct mvtvm_ml_model_object json;
+ struct mvtvm_ml_model_object params;
/* TVM runtime callbacks */
struct tvmrt_glow_callback cb;
+ /* TVM Graph Module */
+ TVMModuleHandle graph_module;
+
+ /* Shared object memfd used to load the TVM module */
+ int fd;
+
+ /* TVM Function Handles */
+ TVMFunctionHandle load_params;
+ TVMFunctionHandle set_input_zero_copy;
+ TVMFunctionHandle set_output_zero_copy;
+ TVMFunctionHandle run;
+
/* Model I/O info */
struct cnxk_ml_io_info info;
@@ -86,5 +148,6 @@ void mvtvm_ml_model_io_info_set(struct cnxk_ml_model *model);
struct cnxk_ml_io_info *mvtvm_ml_model_io_info_get(struct cnxk_ml_model *model, uint16_t layer_id);
void mvtvm_ml_model_info_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *model);
void mvtvm_ml_layer_print(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_layer *layer, FILE *fp);
+int mvtvm_ml_model_json_parse(struct cnxk_ml_model *model);
#endif /* _MVTVM_ML_MODEL_H_ */
diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.c b/drivers/ml/cnxk/mvtvm_ml_ops.c
index 80b22460db9..bc47a4bbd75 100644
--- a/drivers/ml/cnxk/mvtvm_ml_ops.c
+++ b/drivers/ml/cnxk/mvtvm_ml_ops.c
@@ -2,7 +2,17 @@
* Copyright (c) 2023 Marvell.
*/
+#include <errno.h>
+#include <linux/limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
#include <dlpack/dlpack.h>
+#include <jansson.h>
#include <rte_common.h>
#include <rte_cycles.h>
@@ -19,6 +29,76 @@
/* ML model macros */
#define MVTVM_ML_MODEL_MEMZONE_NAME "ml_mvtvm_model_mz"
+/* Shared memory file descriptor name */
+#define ML_MODEL_SHMFD_NAME "mvtvm_shmfd"
+
+/* Shared memory file descriptor path */
+#define ML_MODEL_SHMFD_PATH "/proc/%d/fd/%d"
+
+static int
+mvtvm_ml_tvm_func_get(struct cnxk_ml_model *model, TVMModuleHandle module, const char *name,
+ TVMFunctionHandle *func)
+{
+ int ret;
+
+ ret = TVMModGetFunction(module, name, 0, func);
+ if (ret != 0) {
+ plt_err("Model load failed, model_id = %u, ret = %d, msg = %s", model->model_id,
+ ret, TVMGetLastError());
+ return ret;
+ }
+
+ if (*func == NULL) {
+ ret = -ENOENT;
+ plt_err("Model load failed, model_id = %u, function '%s' not found",
+ model->model_id, name);
+ }
+
+ return ret;
+}
+
+static int
+mvtvm_ml_tvm_func_call(struct cnxk_ml_model *model, TVMFunctionHandle func, const char *name,
+ TVMValue *values, int *types, int num_args, TVMValue *ret_val, int *ret_type,
+ int ret_type_code)
+{
+ int ret;
+
+ ret = TVMFuncCall(func, values, types, num_args, ret_val, ret_type);
+ if (ret != 0) {
+ plt_err("Error calling TVM function '%s', model_id = %u, ret = %d, msg = %s", name,
+ model->model_id, ret, TVMGetLastError());
+ return ret;
+ }
+
+ if (*ret_type != ret_type_code) {
+ ret = -EINVAL;
+ plt_err("TVM function '%s' returned unexpected type, model_id = %u, expected = %d, "
+ "actual = %d",
+ name, model->model_id, ret_type_code, *ret_type);
+ }
+
+ return ret;
+}
+
+static void
+mvtvm_ml_tvm_func_free(TVMFunctionHandle *func)
+{
+ if ((func != NULL) && (*func != NULL)) {
+ TVMFuncFree(*func);
+ *func = NULL;
+ }
+}
+
+static void
+mvtvm_ml_tvm_mod_free(TVMModuleHandle *mod)
+{
+ if ((mod != NULL) && (*mod != NULL)) {
+ TVMModFree(*mod);
+ *mod = NULL;
+ }
+}
+
__rte_hot static void
mvtvm_ml_set_poll_addr(struct cnxk_ml_req *req)
{
@@ -30,8 +110,8 @@ mvtvm_ml_model_xstat_name_set(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_mod
uint16_t stat_id, uint16_t entry, char *suffix)
{
snprintf(cnxk_mldev->xstats.entries[stat_id].map.name,
- sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s",
- model->mvtvm.metadata.model.name, model_xstats[entry].name, suffix);
+ sizeof(cnxk_mldev->xstats.entries[stat_id].map.name), "%s-%s-%s", model->name,
+ model_xstats[entry].name, suffix);
}
#define ML_AVG_FOREACH_QP_MVTVM(cnxk_mldev, model, qp_id, value, count) \
@@ -106,43 +186,13 @@ mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *de
dev_info->max_queue_pairs = mvtvm_mldev->max_nb_qpairs;
dev_info->max_desc = ML_MVTVM_MAX_DESC_PER_QP;
- dev_info->max_io = ML_MVTVM_MAX_INPUT_OUTPUT;
+ dev_info->max_io = ML_CNXK_MODEL_MAX_INPUT_OUTPUT;
dev_info->max_segments = ML_MVTVM_MAX_SEGMENTS;
dev_info->align_size = RTE_CACHE_LINE_SIZE;
return 0;
}
-int
-mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf)
-{
- int ret;
-
- RTE_SET_USED(conf);
-
- /* Configure TVMDP library */
- ret = tvmdp_configure(cnxk_mldev->mldev->data->nb_models, rte_get_tsc_cycles);
- if (ret != 0)
- plt_err("TVMDP configuration failed, error = %d", ret);
-
- return ret;
-}
-
-int
-mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev)
-{
- int ret;
-
- RTE_SET_USED(cnxk_mldev);
-
- /* Close TVMDP library configuration */
- ret = tvmdp_close();
- if (ret != 0)
- plt_err("TVMDP close failed, error = %d", ret);
-
- return ret;
-}
-
int
mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp)
{
@@ -159,16 +209,26 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *
struct mvtvm_ml_model_object object[ML_MVTVM_MODEL_OBJECT_MAX];
struct tvmrt_glow_callback *callback;
char str[RTE_MEMZONE_NAMESIZE];
+ char path[PATH_MAX];
const struct plt_memzone *mz;
size_t model_object_size = 0;
size_t model_xstats_size = 0;
- uint16_t nb_mrvl_layers;
- uint16_t nb_llvm_layers;
- uint8_t layer_id = 0;
uint64_t mz_size = 0;
+ TVMFunctionHandle create_fn = NULL;
+ TVMFunctionHandle register_cb_fn = NULL;
+ TVMModuleHandle module_so = NULL;
+ TVMByteArray tvm_params;
+ TVMValue ret_value = {0};
+ TVMValue arg_values[4] = {0};
+ TVMValue tvm_arg_values[1] = {0};
+ int ret_type = kTVMNullptr;
+ int arg_types[4] = {0};
+ int tvm_arg_types[1] = {0};
+ DLDevice device;
int ret;
RTE_SET_USED(cnxk_mldev);
+ model->mvtvm.fd = -1;
ret = mvtvm_ml_model_blob_parse(params, object);
if (ret != 0)
@@ -192,80 +252,39 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *
}
/* Copy mod.so */
- model->mvtvm.object.so.addr = mz->addr;
- model->mvtvm.object.so.size = object[0].size;
- rte_memcpy(model->mvtvm.object.so.name, object[0].name, TVMDP_NAME_STRLEN);
- rte_memcpy(model->mvtvm.object.so.addr, object[0].buffer, object[0].size);
+ model->mvtvm.so.buffer = mz->addr;
+ model->mvtvm.so.size = object[0].size;
+ rte_memcpy(model->mvtvm.so.name, object[0].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->mvtvm.so.buffer, object[0].buffer, object[0].size);
rte_free(object[0].buffer);
/* Copy mod.json */
- model->mvtvm.object.json.addr =
- RTE_PTR_ADD(model->mvtvm.object.so.addr,
- RTE_ALIGN_CEIL(model->mvtvm.object.so.size, RTE_CACHE_LINE_MIN_SIZE));
- model->mvtvm.object.json.size = object[1].size;
- rte_memcpy(model->mvtvm.object.json.name, object[1].name, TVMDP_NAME_STRLEN);
- rte_memcpy(model->mvtvm.object.json.addr, object[1].buffer, object[1].size);
+ model->mvtvm.json.buffer =
+ RTE_PTR_ADD(model->mvtvm.so.buffer,
+ RTE_ALIGN_CEIL(model->mvtvm.so.size, RTE_CACHE_LINE_MIN_SIZE));
+ model->mvtvm.json.size = object[1].size;
+ rte_memcpy(model->mvtvm.json.name, object[1].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->mvtvm.json.buffer, object[1].buffer, object[1].size);
rte_free(object[1].buffer);
/* Copy mod.params */
- model->mvtvm.object.params.addr =
- RTE_PTR_ADD(model->mvtvm.object.json.addr,
- RTE_ALIGN_CEIL(model->mvtvm.object.json.size, RTE_CACHE_LINE_MIN_SIZE));
- model->mvtvm.object.params.size = object[2].size;
- rte_memcpy(model->mvtvm.object.params.name, object[2].name, TVMDP_NAME_STRLEN);
- rte_memcpy(model->mvtvm.object.params.addr, object[2].buffer, object[2].size);
+ model->mvtvm.params.buffer =
+ RTE_PTR_ADD(model->mvtvm.json.buffer,
+ RTE_ALIGN_CEIL(model->mvtvm.json.size, RTE_CACHE_LINE_MIN_SIZE));
+ model->mvtvm.params.size = object[2].size;
+ rte_memcpy(model->mvtvm.params.name, object[2].name, RTE_ML_STR_MAX);
+ rte_memcpy(model->mvtvm.params.buffer, object[2].buffer, object[2].size);
rte_free(object[2].buffer);
- /* Get metadata - stage 1 */
- ret = tvmdp_model_metadata_get_stage1(model->mvtvm.object.json.addr,
- model->mvtvm.object.json.size,
- &model->mvtvm.metadata);
- if (ret != 0) {
- plt_err("TVMDP: Failed to parse metadata - stage 1, model_id = %u, error = %d",
- model->model_id, ret);
- goto error;
- }
-
- /* Set model fields */
- plt_strlcpy(model->name, model->mvtvm.metadata.model.name, TVMDP_NAME_STRLEN);
- model->batch_size = 1;
- model->nb_layers = model->mvtvm.metadata.model.nb_layers;
-
- /* Update layer info */
- nb_mrvl_layers = 0;
- nb_llvm_layers = 0;
- for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) {
- rte_strscpy(model->layer[layer_id].name,
- model->mvtvm.metadata.model.layer[layer_id].name, TVMDP_NAME_STRLEN);
- if (strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "mrvl") == 0 ||
- strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "MRVL") == 0) {
- model->layer[layer_id].type = ML_CNXK_LAYER_TYPE_MRVL;
- nb_mrvl_layers++;
- } else if (strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "llvm") == 0 ||
- strcmp(model->mvtvm.metadata.model.layer[layer_id].type, "LLVM") == 0) {
- model->layer[layer_id].type = ML_CNXK_LAYER_TYPE_LLVM;
- nb_llvm_layers++;
- }
- }
-
- if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 0)) {
- plt_err("Invalid model, nb_llvm_layers = %u, nb_mrvl_layers = %u", nb_llvm_layers,
- nb_mrvl_layers);
+ ret = mvtvm_ml_model_json_parse(model);
+ if (ret != 0)
goto error;
- }
-
- /* Set model subtype */
- if ((nb_llvm_layers == 0) && (nb_mrvl_layers == 1))
- model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_MRVL;
- else if ((nb_llvm_layers > 0) && (nb_mrvl_layers == 0))
- model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_LLVM;
- else
- model->subtype = ML_CNXK_MODEL_SUBTYPE_TVM_HYBRID;
if (cnxk_mldev->type == CNXK_ML_DEV_TYPE_VDEV &&
model->subtype != ML_CNXK_MODEL_SUBTYPE_TVM_LLVM) {
plt_err("Unsupported model sub-type");
- return -ENOTSUP;
+ ret = -ENOTSUP;
+ goto error;
}
/* Set callback function array */
@@ -284,23 +303,120 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *
callback = NULL;
}
- /* Initialize model in TVMDP */
- ret = tvmdp_model_load(cnxk_mldev, model->model_id, (void *)(&model->mvtvm.object),
- callback);
+ /* Initialize model in TVM runtime */
+ if (model->mvtvm.graph_module != NULL) {
+ ret = -EBUSY;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ snprintf(path, sizeof(path), "%s_%d_%u", ML_MODEL_SHMFD_NAME, getpid(), model->model_id);
+ model->mvtvm.fd = memfd_create(path, 0);
+ if (model->mvtvm.fd < 0) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ if (write(model->mvtvm.fd, model->mvtvm.so.buffer, model->mvtvm.so.size) !=
+ (ssize_t)model->mvtvm.so.size) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ if (lseek(model->mvtvm.fd, 0, SEEK_SET) < 0) {
+ ret = (errno == 0) ? -EIO : -errno;
+ plt_err("TVM runtime: Model load failed, model_id = %u, error = %d",
+ model->model_id, ret);
+ goto error;
+ }
+
+ snprintf(path, sizeof(path), ML_MODEL_SHMFD_PATH, getpid(), model->mvtvm.fd);
+ ret = TVMModLoadFromFile(path, "so", &module_so);
if (ret != 0) {
- plt_err("TVMDP: Model load failed, model_id = %u, error = %d", model->model_id,
- ret);
+ plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
+ model->model_id, ret, TVMGetLastError());
goto error;
}
- /* Get model metadata - stage 2 */
- ret = tvmdp_model_metadata_get_stage2(model->model_id, &model->mvtvm.metadata);
+ /* Set device info */
+ device.device_type = kDLCPU;
+ device.device_id = 0;
+
+ if (callback != NULL) {
+ ret = mvtvm_ml_tvm_func_get(model, module_so, "register_cb", ®ister_cb_fn);
+ if (ret != 0)
+ goto error;
+
+ arg_values[0].v_handle = callback;
+ arg_types[0] = kTVMOpaqueHandle;
+ arg_values[1].v_handle = cnxk_mldev;
+ arg_types[1] = kTVMOpaqueHandle;
+ arg_values[2].v_int64 = model->model_id;
+ arg_types[2] = kDLInt;
+
+ ret = mvtvm_ml_tvm_func_call(model, register_cb_fn, "register_cb", arg_values,
+ arg_types, 3, &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto error;
+ }
+
+ ret = TVMFuncGetGlobal("tvm.graph_executor.create", &create_fn);
if (ret != 0) {
- plt_err("TVMDP: Failed to get metadata, model_id = %u, error = %d",
- model->model_id, ret);
+ plt_err("TVM runtime: Model load failed, model_id = %u, ret = %d, msg = %s",
+ model->model_id, ret, TVMGetLastError());
goto error;
}
+ arg_values[0].v_str = (const char *)model->mvtvm.json.buffer;
+ arg_types[0] = kTVMStr;
+ arg_values[1].v_handle = module_so;
+ arg_types[1] = kTVMModuleHandle;
+ arg_values[2].v_int64 = device.device_type;
+ arg_types[2] = kDLInt;
+ arg_values[3].v_int64 = device.device_id;
+ arg_types[3] = kDLInt;
+
+ ret = mvtvm_ml_tvm_func_call(model, create_fn, "tvm.graph_executor.create", arg_values,
+ arg_types, 4, &ret_value, &ret_type, kTVMModuleHandle);
+ if (ret != 0)
+ goto error;
+ model->mvtvm.graph_module = ret_value.v_handle;
+
+ ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "load_params",
+ &model->mvtvm.load_params);
+ if (ret != 0)
+ goto error;
+ ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_input_zero_copy",
+ &model->mvtvm.set_input_zero_copy);
+ if (ret != 0)
+ goto error;
+ ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "set_output_zero_copy",
+ &model->mvtvm.set_output_zero_copy);
+ if (ret != 0)
+ goto error;
+ ret = mvtvm_ml_tvm_func_get(model, model->mvtvm.graph_module, "run", &model->mvtvm.run);
+ if (ret != 0)
+ goto error;
+
+ mvtvm_ml_tvm_func_free(®ister_cb_fn);
+ mvtvm_ml_tvm_mod_free(&module_so);
+
+ /* Load model parameters into TVM runtime */
+ tvm_params.data = (const char *)model->mvtvm.params.buffer;
+ tvm_params.size = model->mvtvm.params.size;
+ tvm_arg_values[0].v_handle = &tvm_params;
+ tvm_arg_types[0] = kTVMBytes;
+
+ ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.load_params, "load_params", tvm_arg_values,
+ tvm_arg_types, 1, &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto error;
+
/* Update model I/O data */
mvtvm_ml_model_io_info_set(model);
@@ -310,9 +426,9 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *
/* Update model xstats name */
cnxk_ml_xstats_model_name_update(cnxk_mldev, model->model_id);
- model->mvtvm.burst_xstats = RTE_PTR_ADD(
- model->mvtvm.object.params.addr,
- RTE_ALIGN_CEIL(model->mvtvm.object.params.size, RTE_CACHE_LINE_MIN_SIZE));
+ model->mvtvm.burst_xstats =
+ RTE_PTR_ADD(model->mvtvm.params.buffer,
+ RTE_ALIGN_CEIL(model->mvtvm.params.size, RTE_CACHE_LINE_MIN_SIZE));
for (int qp_id = 0; qp_id < cnxk_mldev->mldev->data->nb_queue_pairs; qp_id++) {
model->mvtvm.burst_xstats[qp_id].tvm_rt_latency_tot = 0;
@@ -341,7 +457,20 @@ mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *
return 0;
error:
- rte_memzone_free(mz);
+ mvtvm_ml_tvm_func_free(®ister_cb_fn);
+ if (model != NULL) {
+ mvtvm_ml_tvm_func_free(&model->mvtvm.load_params);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.run);
+ mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module);
+ if (model->mvtvm.fd >= 0)
+ close(model->mvtvm.fd);
+ memset(&model->mvtvm, 0, sizeof(model->mvtvm));
+ model->mvtvm.fd = -1;
+ }
+ mvtvm_ml_tvm_mod_free(&module_so);
+ plt_memzone_free(mz);
return ret;
}
@@ -351,20 +480,28 @@ mvtvm_ml_model_unload(struct cnxk_ml_dev *cnxk_mldev, struct cnxk_ml_model *mode
{
char str[RTE_MEMZONE_NAMESIZE];
const struct plt_memzone *mz;
- int ret;
RTE_SET_USED(cnxk_mldev);
- /* Initialize model in TVMDP */
- ret = tvmdp_model_unload(model->model_id);
- if (ret != 0) {
- plt_err("TVMDP: Model unload failed, model_id = %u, error = %d", model->model_id,
- ret);
- return ret;
- }
+ /* Unload model from TVM runtime */
+ if (model->model_id >= cnxk_mldev->mldev->data->nb_models)
+ return -EINVAL;
+
+ if (model->mvtvm.graph_module == NULL)
+ return -EINVAL;
+
+ mvtvm_ml_tvm_func_free(&model->mvtvm.load_params);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.set_input_zero_copy);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.set_output_zero_copy);
+ mvtvm_ml_tvm_func_free(&model->mvtvm.run);
+ mvtvm_ml_tvm_mod_free(&model->mvtvm.graph_module);
+ if (model->mvtvm.fd >= 0)
+ close(model->mvtvm.fd);
+ memset(&model->mvtvm, 0, sizeof(model->mvtvm));
+ model->mvtvm.fd = -1;
snprintf(str, RTE_MEMZONE_NAMESIZE, "%s_%u", MVTVM_ML_MODEL_MEMZONE_NAME, model->model_id);
- mz = rte_memzone_lookup(str);
+ mz = plt_memzone_lookup(str);
if (mz == NULL) {
plt_err("Memzone lookup failed for TVM model: model_id = %u, mz = %s",
model->model_id, str);
@@ -455,13 +592,13 @@ mvtvm_ml_io_quantize(void *device, uint16_t model_id, const char *layer_name,
#endif
/* Get layer id */
- for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) {
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (strcmp(model->layer[layer_id].name, layer_name) == 0)
break;
}
#ifdef CNXK_ML_DEV_DEBUG
- if (layer_id == model->mvtvm.metadata.model.nb_layers) {
+ if (layer_id == model->nb_layers) {
plt_err("Invalid layer name: %s", layer_name);
return -EINVAL;
}
@@ -516,13 +653,13 @@ mvtvm_ml_io_dequantize(void *device, uint16_t model_id, const char *layer_name,
}
#endif
- for (layer_id = 0; layer_id < model->mvtvm.metadata.model.nb_layers; layer_id++) {
+ for (layer_id = 0; layer_id < model->nb_layers; layer_id++) {
if (strcmp(model->layer[layer_id].name, layer_name) == 0)
break;
}
#ifdef CNXK_ML_DEV_DEBUG
- if (layer_id == model->mvtvm.metadata.model.nb_layers) {
+ if (layer_id == model->nb_layers) {
plt_err("Invalid layer name: %s", layer_name);
return -EINVAL;
}
@@ -553,28 +690,69 @@ static int
mvtvm_ml_model_run(struct cnxk_ml_model *model, struct rte_ml_op *op, struct cnxk_ml_req *req)
{
uint8_t i;
+ struct mvtvm_ml_result *run_result;
+ TVMValue arg_values[2] = {0};
+ int arg_types[2] = {0};
+ TVMValue ret_value = {0};
+ int ret_type = kTVMNullptr;
+ int ret = 0;
rte_memcpy(req->mvtvm_req.input_tensor, model->mvtvm.input_tensor,
- model->mvtvm.metadata.model.num_input * sizeof(DLTensor));
- for (i = 0; i < model->mvtvm.metadata.model.num_input; i++) {
+ model->mvtvm.info.nb_inputs * sizeof(DLTensor));
+ for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
req->mvtvm_req.input_tensor[i].data = op->input[i]->addr;
req->mvtvm_req.input_tensor[i].byte_offset = 0;
}
rte_memcpy(req->mvtvm_req.output_tensor, model->mvtvm.output_tensor,
- model->mvtvm.metadata.model.num_output * sizeof(DLTensor));
- for (i = 0; i < model->mvtvm.metadata.model.num_output; i++) {
+ model->mvtvm.info.nb_outputs * sizeof(DLTensor));
+ for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
req->mvtvm_req.output_tensor[i].data = op->output[i]->addr;
req->mvtvm_req.output_tensor[i].byte_offset = 0;
}
- tvmdp_model_run(model->model_id, model->mvtvm.metadata.model.num_input,
- req->mvtvm_req.input_tensor, model->mvtvm.metadata.model.num_output,
- req->mvtvm_req.output_tensor, &req->mvtvm_req.result,
- &req->mvtvm_req.status);
+ run_result = &req->mvtvm_req.result;
+ run_result->stats.start_ns = rte_get_tsc_cycles();
+ run_result->error_code = 0;
+
+ for (i = 0; i < model->mvtvm.info.nb_inputs; i++) {
+ arg_values[0].v_int64 = i;
+ arg_types[0] = kDLInt;
+ arg_values[1].v_handle = &req->mvtvm_req.input_tensor[i];
+ arg_types[1] = kTVMDLTensorHandle;
+ ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_input_zero_copy,
+ "set_input_zero_copy", arg_values, arg_types, 2,
+ &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+ }
+
+ for (i = 0; i < model->mvtvm.info.nb_outputs; i++) {
+ arg_values[0].v_int64 = i;
+ arg_types[0] = kDLInt;
+ arg_values[1].v_handle = &req->mvtvm_req.output_tensor[i];
+ arg_types[1] = kTVMDLTensorHandle;
+ ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.set_output_zero_copy,
+ "set_output_zero_copy", arg_values, arg_types, 2,
+ &ret_value, &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+ }
+
+ ret = mvtvm_ml_tvm_func_call(model, model->mvtvm.run, "run", NULL, NULL, 0, &ret_value,
+ &ret_type, kTVMNullptr);
+ if (ret != 0)
+ goto out;
+
+out:
+ run_result->stats.end_ns = rte_get_tsc_cycles();
+ req->mvtvm_req.status = 0x1;
plt_write64(ML_CNXK_POLL_JOB_FINISH, req->status);
+ if (ret != 0)
+ run_result->error_code = -EIO;
+
return 0;
}
diff --git a/drivers/ml/cnxk/mvtvm_ml_ops.h b/drivers/ml/cnxk/mvtvm_ml_ops.h
index d8f2f361fb1..593f4585b3c 100644
--- a/drivers/ml/cnxk/mvtvm_ml_ops.h
+++ b/drivers/ml/cnxk/mvtvm_ml_ops.h
@@ -7,11 +7,10 @@
#include <dlpack/dlpack.h>
-#include <tvmdp.h>
-
#include <rte_mldev.h>
#include "cnxk_ml_xstats.h"
+#include "mvtvm_ml_model.h"
struct cnxk_ml_dev;
struct cnxk_ml_model;
@@ -56,8 +55,6 @@ struct mvtvm_ml_req {
};
int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *mldev, struct rte_ml_dev_info *dev_info);
-int mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf);
-int mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev);
int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp);
int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
struct cnxk_ml_model *model);
diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.c b/drivers/ml/cnxk/mvtvm_ml_stubs.c
index 126a954c916..7c13fac42d6 100644
--- a/drivers/ml/cnxk/mvtvm_ml_stubs.c
+++ b/drivers/ml/cnxk/mvtvm_ml_stubs.c
@@ -76,23 +76,6 @@ mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *de
return -ENOTSUP;
}
-int
-mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf)
-{
- RTE_SET_USED(cnxk_mldev);
- RTE_SET_USED(conf);
-
- return 0;
-}
-
-int
-mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev)
-{
- RTE_SET_USED(cnxk_mldev);
-
- return 0;
-}
-
int
mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp)
{
diff --git a/drivers/ml/cnxk/mvtvm_ml_stubs.h b/drivers/ml/cnxk/mvtvm_ml_stubs.h
index 4220a963f2d..15985a75bf4 100644
--- a/drivers/ml/cnxk/mvtvm_ml_stubs.h
+++ b/drivers/ml/cnxk/mvtvm_ml_stubs.h
@@ -15,8 +15,6 @@ struct cnxk_ml_layer;
enum cnxk_ml_model_type mvtvm_ml_model_type_get(struct rte_ml_model_params *params);
int mvtvm_ml_dev_info_get(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_dev_info *dev_info);
-int mvtvm_ml_dev_configure(struct cnxk_ml_dev *cnxk_mldev, const struct rte_ml_dev_config *conf);
-int mvtvm_ml_dev_close(struct cnxk_ml_dev *cnxk_mldev);
int mvtvm_ml_dev_dump(struct cnxk_ml_dev *cnxk_mldev, FILE *fp);
int mvtvm_ml_model_load(struct cnxk_ml_dev *cnxk_mldev, struct rte_ml_model_params *params,
struct cnxk_ml_model *model);
--
2.34.1
^ permalink raw reply related
* [PATCH 1/1] buildtools: remove absolute paths from pc file
From: Srikanth Yalavarthi @ 2026-06-09 4:32 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, Srikanth Yalavarthi
When linking with non-versioned libraries, absolute paths
of the libraries are added to libdpdk.pc. This patch replaces
the absolute path with correct linker flags, -l<libname>.
https://github.com/mesonbuild/meson/issues/7766
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
buildtools/pkg-config/set-static-linker-flags.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/buildtools/pkg-config/set-static-linker-flags.py b/buildtools/pkg-config/set-static-linker-flags.py
index 2745db34c29..bd217b07fc8 100644
--- a/buildtools/pkg-config/set-static-linker-flags.py
+++ b/buildtools/pkg-config/set-static-linker-flags.py
@@ -6,9 +6,16 @@
# Should be called from meson build itself
import os
import sys
+import re
def fix_ldflag(f):
+ if f.startswith('/'):
+ libfile = os.path.basename(f)
+ m = re.match(r'^lib(.+?)\.(a|so(?:\..*)?)$', libfile)
+ if m:
+ return '-l' + m.group(1)
+
if not f.startswith('-lrte_'):
return f
return '-l:lib' + f[2:] + '.a'
--
2.34.1
^ permalink raw reply related
* [PATCH 1/1] mldev: fix typos in code documentation
From: Srikanth Yalavarthi @ 2026-06-09 4:05 UTC (permalink / raw)
To: Srikanth Yalavarthi, Jerin Jacob; +Cc: dev, sshankarnara, ptakkar, aprabhu
Fix typos in MLDEV spec and code documentation.
Fixes: d82cac584f84 ("mldev: introduce machine learning device API")
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
lib/mldev/rte_mldev.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/mldev/rte_mldev.h b/lib/mldev/rte_mldev.h
index 3f51083cb7d..594c46cf72c 100644
--- a/lib/mldev/rte_mldev.h
+++ b/lib/mldev/rte_mldev.h
@@ -497,7 +497,7 @@ struct __rte_cache_aligned rte_ml_op {
*
* The rte_ml_enqueue_burst() function returns the number of inferences it
* actually enqueued for processing. A return value equal to *nb_ops* means that
- * all packets have been enqueued.
+ * all inferences have been enqueued.
*
* @param dev_id
* The identifier of the device.
@@ -540,7 +540,7 @@ rte_ml_enqueue_burst(int16_t dev_id, uint16_t qp_id, struct rte_ml_op **ops, uin
* @param dev_id
* The identifier of the device.
* @param qp_id
- * The index of the queue pair from which to retrieve processed packets.
+ * The index of the queue pair from which to retrieve processed inferences.
* The value must be in the range [0, nb_queue_pairs - 1] previously supplied to
* rte_ml_dev_configure().
* @param ops
@@ -840,7 +840,7 @@ rte_ml_model_unload(int16_t dev_id, uint16_t model_id);
* Identifier of the model to be started.
*
* @return
- * - 0: Success, Model loaded.
+ * - 0: Success, Model started.
* - < 0: Failure, Error code of the model start driver function.
*/
__rte_experimental
@@ -859,7 +859,7 @@ rte_ml_model_start(int16_t dev_id, uint16_t model_id);
* Identifier of the model to be stopped.
*
* @return
- * - 0: Success, Model unloaded.
+ * - 0: Success, Model stopped.
* - < 0: Failure, Error code of the model stop driver function.
*/
__rte_experimental
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/1] ml/cnxk: fix overwriting layer name during load
From: Srikanth Yalavarthi @ 2026-06-09 3:52 UTC (permalink / raw)
To: Srikanth Yalavarthi; +Cc: dev, jerinj
In-Reply-To: <20260331085445.1105590-1-syalavarthi@marvell.com>
Layer name is initialized during metadata fetch and parsing
stage and should not be overwritten during model load. Fix
overwriting the layer name during layer load.
Fixes: cc254869ae19 ("ml/cnxk: update model load/unload functions")
Signed-off-by: Srikanth Yalavarthi <syalavarthi@marvell.com>
---
v2:
* Updated commit message with fixline
v1:
* Initial patch
drivers/ml/cnxk/cn10k_ml_ops.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/ml/cnxk/cn10k_ml_ops.c b/drivers/ml/cnxk/cn10k_ml_ops.c
index b30af7c7a44..cb9e6561442 100644
--- a/drivers/ml/cnxk/cn10k_ml_ops.c
+++ b/drivers/ml/cnxk/cn10k_ml_ops.c
@@ -671,9 +671,6 @@ cn10k_ml_layer_load(void *device, uint16_t model_id, const char *layer_name, uin
rte_memcpy(&layer->glow.metadata, buffer, sizeof(struct cn10k_ml_model_metadata));
cn10k_ml_model_metadata_update(&layer->glow.metadata);
- /* Set layer name */
- rte_memcpy(layer->name, layer->glow.metadata.model.name, MRVL_ML_MODEL_NAME_LEN);
-
/* Enable support for batch_size of 256 */
if (layer->glow.metadata.model.batch_size == 0)
layer->batch_size = 256;
--
2.34.1
^ permalink raw reply related
* [PATCH v14 19/20] drivers: add testpmd commands for private features
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
Introduce private testpmd commands and implementation files to enable
debugging and testing of sxe2-specific hardware features (such as
packet scheduling reset, UDP tunnel configuration, and IPsec ingress/
egress offloads) directly within the testpmd application.
The parameters are parsed using the standard 'rte_kvargs' library during
the PCI/vdev probing phase. Documentation for these parameters is also
updated.
During memory hotplug events, the SXE2 driver needs to track memory
segment layout changes to maintain internal DMA mappings. However,
existing memseg walk functions (rte_memseg_walk) acquire memory locks
and cannot be called from within memory event callbacks, leading to
potential deadlocks.
This commit introduces sxe2_memseg_walk_cb() as a helper that walks
memory segments using the thread-unsafe variant
rte_memseg_walk_thread_unsafe(), which is safe to call from
memory-related callbacks [citation:1][citation:3][citation:5].
The implementation follows the standard rte_memseg_walk_t prototype,
processing each memseg to update driver-specific data structures.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/common/sxe2/sxe2_common.c | 110 +++
drivers/common/sxe2/sxe2_common.h | 2 +
drivers/common/sxe2/sxe2_ioctl_chnl.c | 2 +-
drivers/net/sxe2/meson.build | 5 +-
drivers/net/sxe2/sxe2_cmd_chnl.c | 21 +
drivers/net/sxe2/sxe2_cmd_chnl.h | 3 +
drivers/net/sxe2/sxe2_drv_cmd.h | 17 +
drivers/net/sxe2/sxe2_dump.c | 15 +
drivers/net/sxe2/sxe2_ethdev.c | 287 +++++++-
drivers/net/sxe2/sxe2_ethdev.h | 8 +
drivers/net/sxe2/sxe2_irq.c | 34 +-
drivers/net/sxe2/sxe2_rx.c | 12 +
drivers/net/sxe2/sxe2_testpmd.c | 733 +++++++++++++++++++
drivers/net/sxe2/sxe2_testpmd_lib.c | 969 ++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_testpmd_lib.h | 142 ++++
drivers/net/sxe2/sxe2_tm.c | 18 +
drivers/net/sxe2/sxe2_tm.h | 2 +
17 files changed, 2374 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/sxe2/sxe2_testpmd.c
create mode 100644 drivers/net/sxe2/sxe2_testpmd_lib.c
create mode 100644 drivers/net/sxe2/sxe2_testpmd_lib.h
diff --git a/drivers/common/sxe2/sxe2_common.c b/drivers/common/sxe2/sxe2_common.c
index c000a55cd0..5c5db85f29 100644
--- a/drivers/common/sxe2/sxe2_common.c
+++ b/drivers/common/sxe2/sxe2_common.c
@@ -196,6 +196,102 @@ static int32_t sxe2_parse_representor(const char *key, const char *value, void *
PMD_LOG_INFO(COM, "representor arg %s: \"%s\".", key, value);
+l_end:
+ return ret;
+}
+static int32_t sxe2_dma_mem_map(struct sxe2_common_device *cdev,
+ const void *addr, size_t len, bool do_map)
+{
+ struct rte_memseg_list *msl;
+ struct rte_memseg *ms;
+ size_t cur_len = 0;
+ int32_t ret = 0;
+
+ msl = rte_mem_virt2memseg_list(addr);
+ if (msl == NULL) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(COM, "Invalid virt addr=%p.", addr);
+ goto l_end;
+ }
+
+ if ((uintptr_t)addr != RTE_ALIGN((uintptr_t)addr, msl->page_sz) ||
+ (len != RTE_ALIGN(len, msl->page_sz))) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(COM, "Addr=%p and len=%zu not align page size=%" PRIu64 ".",
+ addr, len, msl->page_sz);
+ goto l_end;
+ }
+
+ /* memsegs are contiguous in memory */
+ ms = rte_mem_virt2memseg(addr, msl);
+ while (cur_len < len) {
+ /* some memory segments may have invalid IOVA */
+ if (ms->iova == RTE_BAD_IOVA) {
+ PMD_LOG_WARN(COM, "Memory segment at %p has bad IOVA, skipping.",
+ ms->addr);
+ goto next;
+ }
+ if (do_map)
+ sxe2_drv_dev_dma_map(cdev, ms->addr_64,
+ ms->iova, ms->len);
+ else
+ sxe2_drv_dev_dma_unmap(cdev, ms->iova);
+
+next:
+ cur_len += ms->len;
+ ++ms;
+ }
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_INTERNAL_SYMBOL(sxe2_common_mem_event_cb)
+void
+sxe2_common_mem_event_cb(enum rte_mem_event type,
+ const void *addr, size_t size, void *arg __rte_unused)
+{
+ struct sxe2_common_device *cdev = NULL;
+
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+ goto l_end;
+
+ pthread_mutex_lock(&sxe2_common_devices_list_lock);
+ switch (type) {
+ case RTE_MEM_EVENT_FREE:
+ TAILQ_FOREACH(cdev, &sxe2_common_devices_list, next)
+ (void)sxe2_dma_mem_map(cdev, addr, size, 0);
+ break;
+ case RTE_MEM_EVENT_ALLOC:
+ TAILQ_FOREACH(cdev, &sxe2_common_devices_list, next)
+ (void)sxe2_dma_mem_map(cdev, addr, size, 1);
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_unlock(&sxe2_common_devices_list_lock);
+l_end:
+ return;
+}
+
+static int32_t sxe2_memseg_walk_cb(const struct rte_memseg_list *msl,
+ const struct rte_memseg *ms, void *arg)
+{
+ struct sxe2_common_device *cdev = arg;
+ int32_t ret = 0;
+
+ if (msl->external && !msl->heap)
+ goto l_end;
+
+ if (ms->iova == RTE_BAD_IOVA)
+ goto l_end;
+
+ ret = sxe2_drv_dev_dma_map(cdev, ms->addr_64, ms->iova, ms->len);
+ if (ret != 0) {
+ PMD_LOG_ERR(COM, "Fail to memseg dma map.");
+ goto l_end;
+ }
+
l_end:
return ret;
}
@@ -220,6 +316,18 @@ static int32_t sxe2_common_device_setup(struct sxe2_common_device *cdev)
goto l_close_dev;
}
+ rte_mcfg_mem_read_lock();
+ ret = rte_memseg_walk_thread_unsafe(sxe2_memseg_walk_cb, cdev);
+ if (ret) {
+ PMD_LOG_ERR(COM, "Fail to walk memseg, ret=%d", ret);
+ rte_mcfg_mem_read_unlock();
+ goto l_close_dev;
+ }
+ rte_mcfg_mem_read_unlock();
+
+ (void)rte_mem_event_callback_register("SXE2_MEM_EVENT_CB",
+ sxe2_common_mem_event_cb, NULL);
+
goto l_end;
l_close_dev:
@@ -251,6 +359,7 @@ static struct sxe2_common_device *sxe2_common_device_alloc(
}
cdev->dev = rte_dev;
cdev->class_type = class_type;
+ cdev->config.cmd_fd = SXE2_CMD_FD_INVALID;
cdev->config.kernel_reset = false;
pthread_mutex_init(&cdev->config.lock, NULL);
@@ -631,6 +740,7 @@ static int32_t sxe2_common_pci_id_table_update(const struct rte_pci_id *id_table
updated_table = calloc(num_ids, sizeof(*updated_table));
if (!updated_table) {
+ ret = -ENOMEM;
PMD_LOG_ERR(COM, "Failed to allocate memory for PCI ID table");
goto l_end;
}
diff --git a/drivers/common/sxe2/sxe2_common.h b/drivers/common/sxe2/sxe2_common.h
index b02b6317da..efc8d3585a 100644
--- a/drivers/common/sxe2/sxe2_common.h
+++ b/drivers/common/sxe2/sxe2_common.h
@@ -14,6 +14,8 @@
#define SXE2_COMMON_PCI_DRIVER_NAME "sxe2_pci"
+#define SXE2_CMD_FD_INVALID (-1)
+
#define SXE2_CDEV_TO_CMD_FD(cdev) \
((cdev)->config.cmd_fd)
diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c
index 173d8d57ae..a233a78136 100644
--- a/drivers/common/sxe2/sxe2_ioctl_chnl.c
+++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c
@@ -110,7 +110,7 @@ sxe2_drv_dev_close(struct sxe2_common_device *cdev)
if (fd >= 0)
close(fd);
PMD_LOG_INFO(COM, "closed device fd=%d", fd);
- SXE2_CDEV_TO_CMD_FD(cdev) = -1;
+ SXE2_CDEV_TO_CMD_FD(cdev) = SXE2_CMD_FD_INVALID;
}
RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_handshake)
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 4fb2333926..04369402b7 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -9,9 +9,10 @@ endif
cflags += ['-g']
-deps += ['common_sxe2', 'hash','cryptodev','security']
+deps += ['common_sxe2', 'hash', 'cryptodev', 'security', 'cmdline']
includes += include_directories('../../common/sxe2')
+testpmd_sources = files('sxe2_testpmd.c')
if arch_subdir == 'x86'
sources += files('sxe2_txrx_vec_sse.c')
@@ -79,5 +80,5 @@ sources += files(
'sxe2_flow_parse_engine.c',
'sxe2_dump.c',
'sxe2_txrx_check_mbuf.c',
-
+ 'sxe2_testpmd_lib.c',
)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 43e8c59487..b09989fe50 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -99,6 +99,27 @@ int32_t sxe2_drv_dev_info_get(struct sxe2_adapter *adapter,
return ret;
}
+int32_t sxe2_drv_fc_state_get(struct sxe2_adapter *adapter,
+ struct sxe2_drv_vsi_fc_get_resp *dev_fc_state_resp)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_drv_vsi_fc_get_req req = {0};
+
+ req.vsi_id = adapter->vsi_ctxt.main_vsi->vsi_id;
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VSI_FC_GET,
+ &req, sizeof(req),
+ dev_fc_state_resp,
+ sizeof(*dev_fc_state_resp));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "get fc state failed, ret=%d", ret);
+ ret = -EIO;
+ }
+ return ret;
+}
+
int32_t sxe2_drv_dev_fw_info_get(struct sxe2_adapter *adapter,
struct sxe2_drv_dev_fw_info_resp *dev_fw_info_resp)
{
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 988d4b458b..d63caad526 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -99,6 +99,9 @@ int32_t sxe2_drv_vsi_stats_reset(struct sxe2_adapter *adapter);
int32_t sxe2_drv_queue_info_get_update(struct sxe2_adapter *adapter,
struct eth_queue_stats *qstats);
+int32_t sxe2_drv_fc_state_get(struct sxe2_adapter *adapter,
+ struct sxe2_drv_vsi_fc_get_resp *dev_fc_state_resp);
+
int32_t sxe2_drv_rxq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx);
int32_t sxe2_drv_txq_mapping_set(struct rte_eth_dev *eth_dev, uint16_t queue_id, uint8_t pool_idx);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 09b2f7d125..59a8aa6f13 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -651,6 +651,23 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_sfp_resp {
uint8_t data[];
} __rte_packed_end;
+enum sxe2_fc_type {
+ SXE2_FC_T_DIS = 0,
+ SXE2_FC_T_LFC,
+ SXE2_FC_T_PFC,
+ SXE2_FC_T_UNKNOWN = 255,
+};
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_fc_get_req {
+ uint16_t vsi_id;
+ uint8_t rsv[2];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vsi_fc_get_resp {
+ uint8_t fc_enable;
+ uint8_t rsv[3];
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_dump.c b/drivers/net/sxe2/sxe2_dump.c
index 1753eccf99..fd0a99d6fd 100644
--- a/drivers/net/sxe2/sxe2_dump.c
+++ b/drivers/net/sxe2/sxe2_dump.c
@@ -188,6 +188,20 @@ static void sxe2_dump_filter_info(FILE *file, struct rte_eth_dev *dev)
return;
}
+static void sxe2_dump_fc_state(FILE *file, struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE))
+ goto l_end;
+
+ fprintf(file, " -- fc state:\n"
+ "\t -- curr_state: %u\n",
+ adapter->fc_state_ctx.curr_state);
+l_end:
+ return;
+}
+
static const char *sxe2_vsi_id_str(uint16_t vsi_id, char *buf, size_t len)
{
if (vsi_id == SXE2_INVALID_VSI_ID)
@@ -274,6 +288,7 @@ int32_t sxe2_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file)
sxe2_dump_dev_args_info(str, dev);
sxe2_dump_filter_info(str, dev);
sxe2_dump_switchdev_info(str, dev);
+ sxe2_dump_fc_state(str, dev);
(void)fflush(str);
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 3c86424c15..b768a780b4 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -68,7 +68,14 @@ static const struct rte_pci_id pci_id_sxe2_tbl[] = {
{ RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_206F, SXE2_PCI_DEVICE_ID_VF_1)},
{ .vendor_id = 0, },
};
-
+#define SXE2_TXSCH_NODE_ADJ_LVL_MAX 3
+#define SXE2_DEVARG_FLOW_DULP_PATTERN_MODE "flow-duplicate-pattern"
+#define SXE2_DEVARG_FUNC_FLOW_DIRCT "function-flow-direct"
+#define SXE2_DEVARG_FNAV_STAT_TYPE "fnav-stat-type"
+#define SXE2_DEVARG_SW_STATS "drv-sw-stats"
+#define SXE2_DEVARG_HIGH_PERFORMANCE_MODE "high-performance-mode"
+#define SXE2_DEVARG_SCHED_LAYER_MODE "sched-layer-mode"
+#define SXE2_DEVARG_RX_LOW_LATENCY "rx-low-latency"
static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_MAX_COUNT] = {
[SXE2_PCI_MAP_RES_INVALID] = {.addr_base = 0,
.bar_idx = 0,
@@ -980,6 +987,149 @@ static inline void sxe2_init_ptype_tbl(struct rte_eth_dev *dev)
sxe2_init_ptype_list(ptype);
}
+static int32_t sxe2_parse_fnav_stat_type(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+ uint8_t *num = (uint8_t *)args;
+ uint8_t fnav_stat_type = 0;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ fnav_stat_type = (uint8_t)strtoul(value, &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.",
+ key, value);
+ goto l_end;
+ }
+ if (fnav_stat_type > SXE2_FNAV_STAT_ENA_ALL ||
+ fnav_stat_type == SXE2_FNAV_STAT_ENA_NONE) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [1-3].",
+ key, value);
+ goto l_end;
+ }
+ *num = fnav_stat_type;
+ ret = 0;
+l_end:
+ return ret;
+}
+static int32_t sxe2_parse_sched_layer_mode(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+ uint8_t *num = (uint8_t *)args;
+ uint8_t sched_layer_mode;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ sched_layer_mode = (uint8_t)strtoul(value, &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.",
+ key, value);
+ goto l_end;
+ }
+ if (sched_layer_mode > SXE2_TXSCH_NODE_ADJ_LVL_MAX) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" > 3.",
+ key, value);
+ goto l_end;
+ }
+ *num = sched_layer_mode;
+ ret = 0;
+l_end:
+ return ret;
+}
+static int32_t sxe2_parse_high_performance_mode(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+ uint8_t *num = (uint8_t *)args;
+ uint8_t high_performance_mode;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ high_performance_mode = (uint8_t)strtoul(value, &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.",
+ key, value);
+ goto l_end;
+ }
+ if (high_performance_mode != 1) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" != 1.",
+ key, value);
+ goto l_end;
+ }
+ *num = high_performance_mode;
+ ret = 0;
+l_end:
+ return ret;
+}
+static int32_t sxe2_parse_u8(const char *key, const char *value, void *args)
+{
+ uint8_t *num = (uint8_t *)args;
+ char *end;
+ unsigned long val;
+ int32_t ret = -EINVAL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ val = strtoul(value, &end, 10);
+ if (errno != 0 || end == value || *end != '\0') {
+ PMD_LOG_ERR(INIT, "Invalid 8-bit integer value for key %s: %s", key, value);
+ return -EINVAL;
+ }
+
+ if (val > UINT8_MAX) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [0-255].",
+ key, value);
+ return -ERANGE;
+ }
+
+ *num = val;
+ ret = 0;
+l_end:
+ return ret;
+}
+static int32_t sxe2_parse_bool(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+ uint8_t *num = (uint8_t *)args;
+ uint8_t bool_val = 0;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ bool_val = (uint8_t)strtoul(value, &endptr, 10);
+ if (errno != 0 || *endptr != '\0') {
+ PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.",
+ key, value);
+ goto l_end;
+ }
+ if (bool_val != 0 && bool_val != 1) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [0|1].",
+ key, value);
+ goto l_end;
+ }
+ *num = bool_val;
+ ret = 0;
+l_end:
+ return ret;
+}
+
struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
enum sxe2_pci_map_resource res_type)
{
@@ -1047,6 +1197,69 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
return addr;
}
+static int32_t sxe2_args_parse(struct rte_eth_dev *dev, struct sxe2_dev_kvargs_info *kvargs)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ PMD_INIT_FUNC_TRACE();
+
+ if (kvargs == NULL)
+ goto l_end;
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FNAV_STAT_TYPE,
+ &sxe2_parse_fnav_stat_type,
+ &adapter->devargs.fnav_stat_type);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse fnav stat type, ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_SW_STATS,
+ &sxe2_parse_bool,
+ &adapter->devargs.sw_stats_en);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse sw stats enable, ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_HIGH_PERFORMANCE_MODE,
+ &sxe2_parse_high_performance_mode,
+ &adapter->devargs.high_performance_mode);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse high performance, ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_SCHED_LAYER_MODE,
+ &sxe2_parse_sched_layer_mode,
+ &adapter->devargs.sched_layer_mode);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse sched layer mode, ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FLOW_DULP_PATTERN_MODE,
+ &sxe2_parse_u8,
+ &adapter->devargs.flow_dup_pattern_mode);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse switch dulpliate flow pattern mode,"
+ "ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FUNC_FLOW_DIRCT,
+ &sxe2_parse_bool,
+ &adapter->devargs.func_flow_direct_en);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse function flow rule enable,"
+ "ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_RX_LOW_LATENCY,
+ &sxe2_parse_bool,
+ &adapter->devargs.rx_low_latency);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse rx low latency, ret:%d", ret);
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
{
int32_t ret = 0;
@@ -1599,6 +1812,37 @@ void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev)
adapter->dev_info.dev_data = NULL;
}
+static int32_t sxe2_fc_state_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter =
+ SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_drv_vsi_fc_get_resp fc_resp = {0};
+ int32_t ret;
+
+ if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE)) {
+ adapter->fc_state_ctx.cfg_state = 0;
+ adapter->fc_state_ctx.curr_state = 0;
+ ret = 0;
+ goto l_end;
+ }
+ ret = sxe2_drv_fc_state_get(adapter, &fc_resp);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get fc state, ret=[%d]", ret);
+ goto l_end;
+ }
+ adapter->fc_state_ctx.cfg_state = fc_resp.fc_enable;
+ adapter->fc_state_ctx.curr_state = 0;
+l_end:
+ return ret;
+}
+static void sxe2_fc_state_uinit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter =
+ SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ adapter->fc_state_ctx.cfg_state = 0;
+ adapter->fc_state_ctx.curr_state = 0;
+}
+
uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter)
{
uint32_t ret_mode = SXE2_SCHED_MODE_INVALID;
@@ -1661,6 +1905,32 @@ static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev)
return ret;
}
+int32_t sxe2_sched_reset(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+
+ if (dev->data->dev_started) {
+ PMD_LOG_ERR(DRV, "Device failed to Stop.");
+ ret = -EPERM;
+ goto l_end;
+ }
+
+ ret = sxe2_tm_conf_reset(dev);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_sched_uinit(dev);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_sched_init(dev);
+ if (ret)
+ goto l_end;
+
+l_end:
+ return ret;
+}
+
static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
struct sxe2_dev_kvargs_info *kvargs __rte_unused)
{
@@ -1683,6 +1953,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
sxe2_init_ptype_tbl(dev);
+ ret = sxe2_args_parse(dev, kvargs);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to parse devargs, ret=%d", ret);
+ goto l_end;
+ }
+
ret = sxe2_hw_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to initialize hw, ret=[%d]", ret);
@@ -1749,6 +2025,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto init_flow_err;
}
+ ret = sxe2_fc_state_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init fc state, ret=%d", ret);
+ goto init_fc_state_err;
+ }
+
ret = sxe2_sched_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret);
@@ -1772,6 +2054,8 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
init_xstats_err:
(void)sxe2_sched_uinit(dev);
init_sched_err:
+ sxe2_fc_state_uinit(dev);
+init_fc_state_err:
(void)sxe2_flow_uninit(dev);
init_flow_err:
init_rss_err:
@@ -1817,6 +2101,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
sxe2_eth_uinit(dev);
sxe2_dev_pci_map_uinit(dev);
sxe2_free_repr_info(dev);
+ sxe2_fc_state_uinit(dev);
l_end:
return 0;
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 510f5139c3..14ad26b439 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -311,6 +311,11 @@ struct sxe2_filter_context {
bool cur_l2_config;
};
+struct sxe2_fc_state_ctxt {
+ uint8_t curr_state;
+ uint8_t cfg_state;
+};
+
struct sxe2_adapter {
struct sxe2_common_device *cdev;
struct sxe2_dev_info dev_info;
@@ -332,6 +337,7 @@ struct sxe2_adapter {
struct sxe2_security_ctx security_ctx;
struct sxe2_repr_context repr_ctxt;
struct sxe2_switchdev_info switchdev_info;
+ struct sxe2_fc_state_ctxt fc_state_ctx;
bool rule_started;
bool flow_isolated;
bool flow_isolate_cfg;
@@ -359,6 +365,8 @@ bool sxe2_ethdev_check(struct rte_eth_dev *dev);
uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter);
+int32_t sxe2_sched_reset(struct rte_eth_dev *dev);
+
struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
enum sxe2_pci_map_resource res_type);
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
index c26098ef3a..3306504761 100644
--- a/drivers/net/sxe2/sxe2_irq.c
+++ b/drivers/net/sxe2/sxe2_irq.c
@@ -10,6 +10,7 @@
#include <rte_alarm.h>
#include <fcntl.h>
#include <rte_stdatomic.h>
+#include <rte_common.h>
#include "sxe2_ethdev.h"
#include "sxe2_irq.h"
@@ -47,6 +48,31 @@ static struct sxe2_event_handler event_handler = {
static RTE_ATOMIC(uint32_t)event_thread_run;
+static int32_t sxe2_fc_state_callback(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_drv_vsi_fc_get_resp fc_resp = {0};
+ int32_t ret;
+
+ if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE)) {
+ ret = 0;
+ goto l_end;
+ }
+ ret = sxe2_drv_fc_state_get(adapter, &fc_resp);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get fc state, ret=[%d]", ret);
+ goto l_end;
+ }
+ adapter->fc_state_ctx.cfg_state = fc_resp.fc_enable;
+ if (dev->data->dev_started) {
+ PMD_LOG_NOTICE(DRV, "Interrupt event: FC status changed."
+ "cfg_state:%u curr_state:%u",
+ adapter->fc_state_ctx.cfg_state,
+ adapter->fc_state_ctx.curr_state);
+ }
+l_end:
+ return ret;
+}
static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t oicr)
{
@@ -68,6 +94,10 @@ static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t
PMD_DEV_LOG_INFO(adapter, DRV, "event notify legacy");
(void)sxe2_switchdev_notify_callback(adapter, false);
}
+ if (oicr & RTE_BIT32(SXE2_COM_FC_ST_CHANGE)) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "fc event notify legacy");
+ (void)sxe2_fc_state_callback(dev);
+ }
}
static uint32_t sxe2_event_intr_handle(void *param __rte_unused)
@@ -436,7 +466,7 @@ int32_t sxe2_intr_init(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter =
SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
- struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev);
+ struct rte_pci_device *pci_dev = container_of(dev->device, struct rte_pci_device, device);
struct rte_intr_handle *reset_handle = NULL;
int32_t ofd = -1;
int32_t rfd = -1;
@@ -518,7 +548,7 @@ void sxe2_intr_uninit(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter =
SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
- struct rte_pci_device *pci_dev = SXE2_DEV_TO_PCI(dev);
+ struct rte_pci_device *pci_dev = container_of(dev->device, struct rte_pci_device, device);
sxe2_reset_intr_unregister(dev);
sxe2_intr_handler_destroy(adapter->irq_ctxt.reset_handle,
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 79e65cfbf1..b5dd9950f0 100644
--- a/drivers/net/sxe2/sxe2_rx.c
+++ b/drivers/net/sxe2/sxe2_rx.c
@@ -467,12 +467,24 @@ int32_t __rte_cold sxe2_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queu
int32_t __rte_cold sxe2_rxqs_all_start(struct rte_eth_dev *dev)
{
struct rte_eth_dev_data *data = dev->data;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_drv_vsi_fc_get_resp fc_resp = {0};
struct sxe2_rx_queue *rxq;
uint16_t nb_rxq;
uint16_t nb_started_rxq;
int32_t ret;
PMD_INIT_FUNC_TRACE();
+ if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE) {
+ ret = sxe2_drv_fc_state_get(adapter, &fc_resp);
+ if (ret) {
+ PMD_LOG_ERR(RX, "Failed to get fc state, ret=[%d]", ret);
+ goto l_end;
+ }
+ adapter->fc_state_ctx.cfg_state = fc_resp.fc_enable;
+ adapter->fc_state_ctx.curr_state = adapter->fc_state_ctx.cfg_state;
+ }
+
for (nb_rxq = 0; nb_rxq < data->nb_rx_queues; nb_rxq++) {
rxq = dev->data->rx_queues[nb_rxq];
if (!rxq || rxq->rx_deferred_start)
diff --git a/drivers/net/sxe2/sxe2_testpmd.c b/drivers/net/sxe2/sxe2_testpmd.c
new file mode 100644
index 0000000000..5792058212
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_testpmd.c
@@ -0,0 +1,733 @@
+
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_TEST
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+#include <stdlib.h>
+#include <testpmd.h>
+
+#include "sxe2_common_log.h"
+#include "sxe2_testpmd_lib.h"
+
+#define SXE2_SWITCH_BUFF_SIZE (4 * 1024 * 1024)
+
+struct cmd_stats_info_show_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t show;
+ cmdline_fixed_string_t stats;
+ portid_t port_id;
+};
+cmdline_parse_token_string_t cmd_stats_info_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_stats_info_show_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_stats_info_show =
+ TOKEN_STRING_INITIALIZER(struct cmd_stats_info_show_result, show, "show");
+cmdline_parse_token_string_t cmd_stats_info_stats =
+ TOKEN_STRING_INITIALIZER(struct cmd_stats_info_show_result, stats, "stats");
+cmdline_parse_token_num_t cmd_stats_info_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_stats_info_show_result, port_id, RTE_UINT16);
+
+struct cmd_flow_rule_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t flow;
+ cmdline_fixed_string_t rule;
+ cmdline_fixed_string_t dump;
+ portid_t port_id;
+};
+cmdline_parse_token_string_t cmd_flow_rule_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_rule_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_flow_rule_flow =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_rule_result, flow, "flow");
+cmdline_parse_token_string_t cmd_flow_rule_rule =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_rule_result, rule, "rule");
+cmdline_parse_token_string_t cmd_flow_rule_dmp =
+ TOKEN_STRING_INITIALIZER(struct cmd_flow_rule_result, dump, "dump");
+cmdline_parse_token_num_t cmd_flow_rule_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_flow_rule_result, port_id, RTE_UINT16);
+
+struct cmd_udp_tunnel {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t tunnel_type;
+ cmdline_fixed_string_t action;
+ cmdline_fixed_string_t udp_tunnel_port;
+ uint16_t udp_port;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_udp_tunnel_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_udp_tunnel, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_udp_tunnel_action =
+ TOKEN_STRING_INITIALIZER(struct cmd_udp_tunnel, action, "add#rm#show");
+cmdline_parse_token_string_t cmd_udp_tunnel_udp_tunnel_port =
+ TOKEN_STRING_INITIALIZER(struct cmd_udp_tunnel, udp_tunnel_port, "udp_tunnel_port");
+cmdline_parse_token_string_t cmd_udp_tunnel_tunnel_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_udp_tunnel,
+ tunnel_type, "vxlan#vxlan-gpe#geneve#gtp-c#gtp-u#pfcp#ecpri#mpls#nvgre#l2tp#teredo");
+cmdline_parse_token_num_t cmd_udp_tunnel_udp_port =
+ TOKEN_NUM_INITIALIZER(struct cmd_udp_tunnel, udp_port, RTE_UINT16);
+cmdline_parse_token_num_t cmd_udp_tunnel_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_udp_tunnel, port_id, RTE_UINT16);
+
+struct cmd_sched_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t sched;
+ cmdline_fixed_string_t reset;
+ portid_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_sched_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_sched_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_sched_sched =
+ TOKEN_STRING_INITIALIZER(struct cmd_sched_result, sched, "sched");
+cmdline_parse_token_string_t cmd_sched_reset =
+ TOKEN_STRING_INITIALIZER(struct cmd_sched_result, reset, "reset");
+cmdline_parse_token_num_t cmd_sched_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_sched_result, port_id, RTE_UINT16);
+
+struct cmd_ipsec_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t engin;
+ cmdline_fixed_string_t dir;
+ cmdline_fixed_string_t op;
+ portid_t port_id;
+ uint16_t session_id;
+ cmdline_fixed_string_t encrypt_algo;
+ cmdline_fixed_string_t encrypt_key;
+ cmdline_fixed_string_t auth_algo;
+ cmdline_fixed_string_t auth_key;
+ cmdline_fixed_string_t dst_ip;
+ uint16_t sport;
+ uint16_t dport;
+ uint32_t spi;
+};
+cmdline_parse_token_string_t cmd_ipsec_mgt_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_ipsec_mgt_module =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, engin, "ipsec");
+cmdline_parse_token_string_t cmd_ipsec_mgt_dir =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, dir, "egress#ingress");
+cmdline_parse_token_string_t cmd_ipsec_mgt_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, op, "add#rm#show");
+cmdline_parse_token_num_t cmd_ipsec_mgt_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_result, port_id, RTE_UINT16);
+cmdline_parse_token_num_t cmd_ipsec_mgt_session_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_result, session_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_ipsec_mgt_encrypt_algo =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, encrypt_algo, "aes-cbc#sm4-cbc#null");
+cmdline_parse_token_string_t cmd_ipsec_mgt_encrypt_key =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, encrypt_key, NULL);
+cmdline_parse_token_string_t cmd_ipsec_mgt_auth_algo =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, auth_algo, "sha-hmac#sm3-hmac#null");
+cmdline_parse_token_string_t cmd_ipsec_mgt_auth_key =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, auth_key, NULL);
+cmdline_parse_token_string_t cmd_ipsec_mgt_dst_ip =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_result, dst_ip, NULL);
+cmdline_parse_token_num_t cmd_ipsec_mgt_sport =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_result, sport, RTE_UINT16);
+cmdline_parse_token_num_t cmd_ipsec_mgt_dport =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_result, dport, RTE_UINT16);
+cmdline_parse_token_num_t cmd_ipsec_mgt_spi =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_result, spi, RTE_UINT32);
+
+struct cmd_ipsec_set_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t engin;
+ cmdline_fixed_string_t op;
+ cmdline_fixed_string_t type;
+ portid_t port_id;
+ uint16_t conf_value;
+};
+cmdline_parse_token_string_t cmd_ipsec_set_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_set_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_ipsec_set_module =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_set_result, engin, "ipsec");
+cmdline_parse_token_string_t cmd_ipsec_set_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_set_result, op, "set#get");
+cmdline_parse_token_string_t cmd_ipsec_set_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_set_result, type, "session-id#esp-hdr-offset");
+cmdline_parse_token_num_t cmd_ipsec_set_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_set_result, port_id, RTE_UINT16);
+cmdline_parse_token_num_t cmd_ipsec_set_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_set_result, conf_value, RTE_UINT16);
+
+struct cmd_ipsec_flush_result {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t engin;
+ cmdline_fixed_string_t op;
+ portid_t port_id;
+};
+cmdline_parse_token_string_t cmd_ipsec_flush_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_flush_result, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_ipsec_flush_module =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_flush_result, engin, "ipsec");
+cmdline_parse_token_string_t cmd_ipsec_flush_op =
+ TOKEN_STRING_INITIALIZER(struct cmd_ipsec_flush_result, op, "flush");
+cmdline_parse_token_num_t cmd_ipsec_flush_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_ipsec_flush_result, port_id, RTE_UINT16);
+
+struct cmd_inject_irq {
+ cmdline_fixed_string_t sxe2;
+ cmdline_fixed_string_t inject;
+ cmdline_fixed_string_t irq;
+ portid_t port_id;
+ cmdline_fixed_string_t type;
+};
+cmdline_parse_token_string_t cmd_inject_irq_sxe2 =
+ TOKEN_STRING_INITIALIZER(struct cmd_inject_irq, sxe2, "sxe2");
+cmdline_parse_token_string_t cmd_inject_irq_inject =
+ TOKEN_STRING_INITIALIZER(struct cmd_inject_irq, inject, "inject");
+cmdline_parse_token_string_t cmd_inject_irq_irq =
+ TOKEN_STRING_INITIALIZER(struct cmd_inject_irq, irq, "irq");
+cmdline_parse_token_num_t cmd_inject_irq_port_id =
+ TOKEN_NUM_INITIALIZER(struct cmd_inject_irq, port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_inject_irq_type =
+ TOKEN_STRING_INITIALIZER(struct cmd_inject_irq, type, "reset#lsc");
+
+static void cmd_dump_flow_rule_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_flow_rule_result *res = parsed_result;
+ int ret = -1;
+
+ ret = sxe2_flow_rule_dump(res->port_id, cl);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ cmdline_printf(cl, "Invalid parameters.\n");
+ break;
+ case -ENODEV:
+ cmdline_printf(cl, "Device doesn't support\n");
+ break;
+ default:
+ cmdline_printf(cl,
+ "Failed to switch rule dump,"
+ " error: (%s)\n",
+ strerror(-ret));
+ }
+}
+
+static void cmd_udp_tunnel_set_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_udp_tunnel *res = parsed_result;
+ int32_t ret = -1;
+ uint8_t action;
+ const char *action_str[SXE2_TESTPMD_CMD_UDP_TUNNEL_MAX] = {
+ [SXE2_TESTPMD_CMD_UDP_TUNNEL_ADD] = "add",
+ [SXE2_TESTPMD_CMD_UDP_TUNNEL_DEL] = "rm",
+ [SXE2_TESTPMD_CMD_UDP_TUNNEL_GET] = "show"};
+
+ for (action = 0; action < SXE2_TESTPMD_CMD_UDP_TUNNEL_MAX; action++)
+ if (!strcmp(res->action, action_str[action]))
+ break;
+
+ if (action >= SXE2_TESTPMD_CMD_UDP_TUNNEL_MAX) {
+ cmdline_printf(cl, "Invalid action!\n");
+ return;
+ }
+
+ ret = sxe2_udp_tunnel_operations(res->port_id, cl, action,
+ res->udp_port,
+ res->tunnel_type);
+ if (ret)
+ cmdline_printf(cl, "%s udp tunnel port failed, ret = %d\n",
+ action_str[action], ret);
+}
+
+static void cmd_dump_stats_info_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_stats_info_show_result *res = parsed_result;
+ int ret = -1;
+
+ ret = sxe2_stats_info_show(res->port_id);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ cmdline_printf(cl, "Invalid parameters.\n");
+ break;
+ case -ENODEV:
+ cmdline_printf(cl, "Device doesn't support\n");
+ break;
+ default:
+ cmdline_printf(cl,
+ "Failed to show stats info,"
+ " error: (%s)\n", strerror(-ret));
+ }
+}
+
+static uint8_t cmd_ipsec_op_get(char *op)
+{
+ uint8_t i;
+ const char *op_type[SXE2_TESTPMD_CMD_IPSEC_OP_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_OP_ADD] = "add",
+ [SXE2_TESTPMD_CMD_IPSEC_OP_RM] = "rm",
+ [SXE2_TESTPMD_CMD_IPSEC_OP_SHOW] = "show",
+ };
+
+ for (i = 0; i < SXE2_TESTPMD_CMD_IPSEC_OP_MAX; i++) {
+ if (!strcmp(op, op_type[i]))
+ break;
+ }
+
+ return i;
+}
+
+static uint8_t cmd_ipsec_dir_get(char *dir)
+{
+ uint8_t i;
+ const char *dir_type[SXE2_TESTPMD_CMD_IPSEC_DIR_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS] = "egress",
+ [SXE2_TESTPMD_CMD_IPSEC_DIR_INGRESS] = "ingress"
+ };
+
+ for (i = 0; i < SXE2_TESTPMD_CMD_IPSEC_DIR_MAX; i++) {
+ if (!strcmp(dir, dir_type[i]))
+ break;
+ }
+
+ return i;
+}
+
+static int sxe2_hex_to_val(char c)
+{
+ int val = 0;
+
+ if (c >= '0' && c <= '9')
+ val = c - '0';
+ if (c >= 'A' && c <= 'F')
+ val = 10 + c - 'A';
+ if (c >= 'a' && c <= 'f')
+ val = 10 + c - 'a';
+ return val;
+}
+
+static void sxe2_hex_to_bytes(uint8_t *enc_key, char *hex_str, uint8_t len)
+{
+ uint8_t i;
+ int high = 0;
+ int low = 0;
+
+ for (i = 0; i < len; i++) {
+ high = sxe2_hex_to_val(hex_str[2 * i]);
+ low = sxe2_hex_to_val(hex_str[2 * i + 1]);
+ enc_key[i] = (high << 4) | low;
+ }
+}
+
+static int32_t cmd_ipsec_add_param_fill(struct sxe2_ipsec_conf_param *param,
+ struct cmdline *cl,
+ struct cmd_ipsec_result *res)
+{
+ uint8_t i;
+ uint8_t j;
+ int32_t ret = -1;
+ const char *encrypt_algo[SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC] = "aes-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_SM4_CBC] = "sm4-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL] = "null"
+ };
+
+ const char *auth_algo[SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC] = "sha-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SM3_HMAC] = "sm3-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL] = "null"
+ };
+
+ for (i = 0; i < SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX; i++)
+ if (!strcmp(res->encrypt_algo, encrypt_algo[i]))
+ break;
+
+ if (i >= SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX) {
+ cmdline_printf(cl, "Invalid ipsec encrypt algo: %s!\n", res->encrypt_algo);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ for (j = 0; j < SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX; j++) {
+ if (!strcmp(res->auth_algo, auth_algo[j]))
+ break;
+ }
+
+
+ if (j >= SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX) {
+ cmdline_printf(cl, "Invalid ipsec auth algo: %s!\n", res->auth_algo);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ param->encrypt_algo = i;
+ param->auth_algo = j;
+ if (param->encrypt_algo == SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_SM4_CBC)
+ param->enc_len = 16;
+ else
+ param->enc_len = 32;
+
+ sxe2_hex_to_bytes(param->enc_key, res->encrypt_key, param->enc_len);
+ if (param->auth_algo != SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL) {
+ param->auth_len = 32;
+ sxe2_hex_to_bytes(param->auth_key, res->auth_key, param->auth_len);
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t cmd_ipsec_egress_op_parsed(struct sxe2_ipsec_conf_param *param,
+ struct cmdline *cl,
+ struct cmd_ipsec_result *res)
+{
+ int32_t ret = -1;
+
+ switch (param->op) {
+ case SXE2_TESTPMD_CMD_IPSEC_OP_ADD:
+ ret = cmd_ipsec_add_param_fill(param, cl, res);
+ if (ret)
+ goto l_end;
+ ret = sxe2_ipsec_egress_create(param, cl);
+ break;
+ case SXE2_TESTPMD_CMD_IPSEC_OP_RM:
+ param->session_id = res->session_id;
+ ret = sxe2_ipsec_egress_destroy(param, cl);
+ break;
+ case SXE2_TESTPMD_CMD_IPSEC_OP_SHOW:
+ ret = sxe2_ipsec_egress_show(param, cl);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t cmd_ipsec_ip_addr_parsed(struct sxe2_ipsec_conf_param *param,
+ struct cmdline *cl,
+ struct cmd_ipsec_result *res)
+{
+ int32_t ret = -1;
+ struct in_addr addr4;
+ struct in6_addr addr6;
+
+ if (inet_pton(AF_INET, res->dst_ip, &addr4) == 1) {
+ param->ip_addr.type = RTE_SECURITY_IPSEC_TUNNEL_IPV4;
+ param->ip_addr.dst_ipv4 = addr4.s_addr;
+ ret = 0;
+ } else if (inet_pton(AF_INET6, res->dst_ip, &addr6) == 1) {
+ param->ip_addr.type = RTE_SECURITY_IPSEC_TUNNEL_IPV6;
+ memcpy(¶m->ip_addr.dst_ipv6, &addr6, sizeof(param->ip_addr.dst_ipv6));
+ ret = 0;
+ } else {
+ cmdline_printf(cl, "Invalid ip address: %s!\n", res->dst_ip);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t cmd_ipsec_ingress_op_parsed(struct sxe2_ipsec_conf_param *param,
+ struct cmdline *cl,
+ struct cmd_ipsec_result *res)
+{
+ int32_t ret = -1;
+
+ switch (param->op) {
+ case SXE2_TESTPMD_CMD_IPSEC_OP_ADD:
+ ret = cmd_ipsec_add_param_fill(param, cl, res);
+ if (ret)
+ goto l_end;
+ param->sport = htons(res->sport);
+ param->dport = htons(res->dport);
+ param->spi = htonl(res->spi);
+ ret = cmd_ipsec_ip_addr_parsed(param, cl, res);
+ if (ret)
+ goto l_end;
+ ret = sxe2_ipsec_ingress_create(param, cl);
+ break;
+ case SXE2_TESTPMD_CMD_IPSEC_OP_RM:
+ param->session_id = res->session_id;
+ ret = sxe2_ipsec_ingress_destroy(param, cl);
+ break;
+ case SXE2_TESTPMD_CMD_IPSEC_OP_SHOW:
+ ret = sxe2_ipsec_ingress_show(param, cl);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t cmd_ipsec_dir_parsed(struct sxe2_ipsec_conf_param *param,
+ struct cmdline *cl,
+ struct cmd_ipsec_result *res)
+{
+ int32_t ret = -1;
+
+ switch (param->dir) {
+ case SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS:
+ ret = cmd_ipsec_egress_op_parsed(param, cl, res);
+ break;
+ case SXE2_TESTPMD_CMD_IPSEC_DIR_INGRESS:
+ ret = cmd_ipsec_ingress_op_parsed(param, cl, res);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void cmd_ipsec_mgt_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ipsec_result *res = parsed_result;
+ struct sxe2_ipsec_conf_param param;
+ int32_t ret = -1;
+ uint8_t dir = 0;
+ uint8_t op = 0;
+
+ dir = cmd_ipsec_dir_get(res->dir);
+ if (dir >= SXE2_TESTPMD_CMD_IPSEC_DIR_MAX) {
+ cmdline_printf(cl, "Invalid ipsec direction: %s!\n", res->dir);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ op = cmd_ipsec_op_get(res->op);
+ if (op >= SXE2_TESTPMD_CMD_IPSEC_OP_MAX) {
+ cmdline_printf(cl, "Invalid ipsec operation: %s!\n", res->op);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ memset(¶m, 0, sizeof(struct sxe2_ipsec_conf_param));
+ param.dir = dir;
+ param.op = op;
+ param.port_id = res->port_id;
+ ret = cmd_ipsec_dir_parsed(¶m, cl, res);
+
+ if (ret)
+ cmdline_printf(cl, "Command execute failed, ret = %d\n", ret);
+
+l_end:
+ return;
+}
+
+static void cmd_ipsec_set_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ipsec_set_result *res = parsed_result;
+ int32_t ret = -1;
+
+ if (!strcmp(res->op, "set"))
+ ret = sxe2_ipsec_conf_set(res->port_id, cl, res->type, res->conf_value);
+ else if (!strcmp(res->op, "get"))
+ ret = sxe2_ipsec_conf_get(res->port_id, cl, res->type);
+ else
+ cmdline_printf(cl, "Invalid op: %s\n", res->op);
+
+ if (ret)
+ cmdline_printf(cl, "Command execute failed, ret = %d\n", ret);
+}
+
+static void cmd_ipsec_flush_parsed(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_ipsec_flush_result *res = parsed_result;
+ int32_t ret = -1;
+
+ ret = sxe2_ipsec_flush(res->port_id, cl);
+
+ if (ret)
+ cmdline_printf(cl, "Command execute failed, ret = %d\n", ret);
+}
+
+cmdline_parse_inst_t cmd_flow_rule_dump = {
+ .f = cmd_dump_flow_rule_parsed,
+ .data = NULL,
+ .help_str = "sxe2 flow rule dump <port_id>",
+ .tokens = {
+ (void *)&cmd_flow_rule_sxe2,
+ (void *)&cmd_flow_rule_flow,
+ (void *)&cmd_flow_rule_rule,
+ (void *)&cmd_flow_rule_dmp,
+ (void *)&cmd_flow_rule_port_id,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_udp_tunnel_set = {
+ .f = cmd_udp_tunnel_set_parsed,
+ .data = NULL,
+ .help_str = "sxe2 <port_id> udp_tunnel_port add|rm|show "
+ "vxlan|vxlan-gpe|geneve|gtp-c|gtp-u|pfcp|ecpri|mpls|nvgre|l2tp|teredo <udp_port>",
+ .tokens = {
+ (void *)&cmd_udp_tunnel_sxe2,
+ (void *)&cmd_udp_tunnel_port_id,
+ (void *)&cmd_udp_tunnel_udp_tunnel_port,
+ (void *)&cmd_udp_tunnel_action,
+ (void *)&cmd_udp_tunnel_tunnel_type,
+ (void *)&cmd_udp_tunnel_udp_port,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_stats_mgt = {
+ .f = cmd_dump_stats_info_parsed,
+ .data = NULL,
+ .help_str = "sxe2 show stats <port_id>",
+ .tokens = {
+ (void *)&cmd_stats_info_sxe2,
+ (void *)&cmd_stats_info_show,
+ (void *)&cmd_stats_info_stats,
+ (void *)&cmd_stats_info_port_id,
+ NULL,
+ },
+};
+
+static void cmd_sched_reset_cfg(void *parsed_result,
+ struct cmdline *cl,
+ __rte_unused void *data)
+{
+ struct cmd_sched_result *res = parsed_result;
+ int32_t ret = -1;
+
+ ret = sxe2_testpmd_sched_reset(res->port_id);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINVAL:
+ cmdline_printf(cl, "invalid sched ops\n");
+ break;
+ case -ENOTSUP:
+ cmdline_printf(cl, "function not implemented\n");
+ break;
+ default:
+ cmdline_printf(cl, "programming error: (%s)\n",
+ strerror(-ret));
+ }
+}
+
+cmdline_parse_inst_t cmd_sched_reset_cmd = {
+ .f = cmd_sched_reset_cfg,
+ .data = NULL,
+ .help_str = "sxe2 sched reset <port_id>",
+ .tokens = {
+ (void *)&cmd_sched_sxe2,
+ (void *)&cmd_sched_sched,
+ (void *)&cmd_sched_reset,
+ (void *)&cmd_sched_port_id,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_ipsec_mgt = {
+ .f = cmd_ipsec_mgt_parsed,
+ .data = NULL,
+ .help_str = "sxe2 ipsec egress|ingress add|rm|show "
+ "<port_id> <session_id> aes-cbc|sm4-cbc|null <encrypt_key> sha-hmac|sm3-hmac|null "
+ "<auth_key> <dst_ip> <sport> <dport> <spi>",
+ .tokens = {
+ (void *)&cmd_ipsec_mgt_sxe2,
+ (void *)&cmd_ipsec_mgt_module,
+ (void *)&cmd_ipsec_mgt_dir,
+ (void *)&cmd_ipsec_mgt_op,
+ (void *)&cmd_ipsec_mgt_port_id,
+ (void *)&cmd_ipsec_mgt_session_id,
+ (void *)&cmd_ipsec_mgt_encrypt_algo,
+ (void *)&cmd_ipsec_mgt_encrypt_key,
+ (void *)&cmd_ipsec_mgt_auth_algo,
+ (void *)&cmd_ipsec_mgt_auth_key,
+ (void *)&cmd_ipsec_mgt_dst_ip,
+ (void *)&cmd_ipsec_mgt_sport,
+ (void *)&cmd_ipsec_mgt_dport,
+ (void *)&cmd_ipsec_mgt_spi,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_ipsec_set = {
+ .f = cmd_ipsec_set_parsed,
+ .data = NULL,
+ .help_str = "sxe2 ipsec set|get esp-hdr-offset|session-id <port_id> <value>",
+ .tokens = {
+ (void *)&cmd_ipsec_set_sxe2,
+ (void *)&cmd_ipsec_set_module,
+ (void *)&cmd_ipsec_set_op,
+ (void *)&cmd_ipsec_set_type,
+ (void *)&cmd_ipsec_set_port_id,
+ (void *)&cmd_ipsec_set_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_ipsec_flush = {
+ .f = cmd_ipsec_flush_parsed,
+ .data = NULL,
+ .help_str = "sxe2 ipsec flush <port_id>.\n",
+ .tokens = {
+ (void *)&cmd_ipsec_flush_sxe2,
+ (void *)&cmd_ipsec_flush_module,
+ (void *)&cmd_ipsec_flush_op,
+ (void *)&cmd_ipsec_flush_port_id,
+ NULL,
+ },
+};
+
+static struct testpmd_driver_commands sxe2_cmds = {
+ .commands = {
+ {
+ &cmd_udp_tunnel_set,
+ "sxe2 udp tunnel port set.\n"
+ "Add or remove a customed udp port for specific tunnel protocol\n\n",
+ },
+ {
+ &cmd_sched_reset_cmd,
+ "sxe2 sched reset <port_id>.\n"
+ "Reset sched node on the port\n\n",
+ },
+ {
+ &cmd_stats_mgt,
+ "sxe2 show stats.\n"
+ "Dump a runtime sxe2 dev stats on a port\n\n",
+ },
+ {
+ &cmd_ipsec_mgt,
+ "sxe2 ipsec <dir> <op> <port_id> <session_id> <encrypt_algo> <encrypt_key>"
+ "<encrypt_len> <auth_algo> <auth_key> <auth_len> <dst_ip> <sport> <dport> <spi>.\n"
+ "Create/query/remove ipsec security session\n\n",
+ },
+ {
+ &cmd_ipsec_set,
+ "sxe2 ipsec set <port_id> <session_id> <esp_hdr_offset>.\n"
+ "Set enabled tx session id or esp offset.\n\n",
+ },
+ {
+ &cmd_ipsec_flush,
+ "sxe2 ipsec flush <port_id>.\n"
+ "Flush ipsec all configurations\n\n",
+ },
+ { NULL, NULL},
+ },
+};
+TESTPMD_ADD_DRIVER_COMMANDS(sxe2_cmds)
+#endif
diff --git a/drivers/net/sxe2/sxe2_testpmd_lib.c b/drivers/net/sxe2/sxe2_testpmd_lib.c
new file mode 100644
index 0000000000..ab2530ffe6
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_testpmd_lib.c
@@ -0,0 +1,969 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_bus.h>
+#include <eal_export.h>
+
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_stats.h"
+#include "sxe2_testpmd_lib.h"
+
+struct rte_mempool *g_sess_pool;
+
+bool g_sxe2_ipsec_mgt_init;
+struct sxe2_ipsec_session_mgt g_tx_session[SXE2_IPSEC_PORT_MAX][SXE2_IPSEC_SESSION_MAX];
+struct sxe2_ipsec_session_mgt g_rx_session[SXE2_IPSEC_PORT_MAX][SXE2_IPSEC_SESSION_MAX];
+uint16_t g_tx_sess_id[SXE2_IPSEC_PORT_MAX] = {0};
+uint16_t g_esp_header_offset[SXE2_IPSEC_PORT_MAX] = {0};
+
+static bool sxe2_is_supported(struct rte_eth_dev *dev)
+{
+ return sxe2_ethdev_check(dev);
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_testpmd_sched_reset, 26.07)
+int32_t
+sxe2_testpmd_sched_reset(uint16_t port_id)
+{
+ struct rte_eth_dev *dev = NULL;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ return -ENODEV;
+ }
+
+ return sxe2_sched_reset(dev);
+}
+
+extern const char *sxe2_flow_type_name[SXE2_FLOW_TYPE_MAX];
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_flow_rule_dump, 26.07)
+int32_t
+sxe2_flow_rule_dump(uint16_t port_id, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct sxe2_adapter *adapter = NULL;
+ int32_t ret = -1;
+ struct rte_flow_list_t *flow_list = NULL;
+ struct rte_flow *flow = NULL;
+ uint32_t index = 0;
+ struct sxe2_flow *hw_flow = NULL;
+ uint8_t i = 0;
+
+ const char *sxe2_flow_engine_name[SXE2_FLOW_ENGINE_MAX] = {
+ [SXE2_FLOW_ENGINE_ACL] = "acl",
+ [SXE2_FLOW_ENGINE_RSS] = "rss",
+ [SXE2_FLOW_ENGINE_SWITCH] = "switch",
+ [SXE2_FLOW_ENGINE_FNAV] = "fnav",
+ };
+ const char *sxe2_flow_action_name[SXE2_FLOW_ACTION_MAX] = {
+ [SXE2_FLOW_ACTION_DROP] = "drop",
+ [SXE2_FLOW_ACTION_TC_REDIRECT] = "tc_redirect",
+ [SXE2_FLOW_ACTION_TO_VSI] = "to_vsi",
+ [SXE2_FLOW_ACTION_TO_VSI_LIST] = "to_vsi_list",
+ [SXE2_FLOW_ACTION_PASSTHRU] = "passthru",
+ [SXE2_FLOW_ACTION_QUEUE] = "queue",
+ [SXE2_FLOW_ACTION_Q_REGION] = "q_region",
+ [SXE2_FLOW_ACTION_MARK] = "mark",
+ [SXE2_FLOW_ACTION_COUNT] = "count",
+ [SXE2_FLOW_ACTION_RSS] = "rss",
+ };
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev");
+ ret = -ENODEV;
+ goto l_end;
+ }
+ adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ flow_list = &adapter->flow_ctxt.rte_flow_list;
+ cmdline_printf(cl, "Dump sxe2 flow rule:\n");
+ TAILQ_FOREACH(flow, flow_list, next) {
+ cmdline_printf(cl, "rule index: %d\n", index++);
+ TAILQ_FOREACH(hw_flow, &flow->sxe2_flow_list, next) {
+ cmdline_printf(cl, "\thw flow id: %d\n", hw_flow->flow_id);
+ cmdline_printf(cl, "\t\ttype: %s\n",
+ sxe2_flow_type_name[hw_flow->meta.flow_type]);
+ cmdline_printf(cl, "\t\tprio: %d\n", hw_flow->meta.flow_prio);
+ cmdline_printf(cl, "\t\tsrc vsi: %d,rule vsi: %d\n",
+ hw_flow->meta.flow_src_vsi, hw_flow->meta.flow_rule_vsi);
+ cmdline_printf(cl, "\t\tengine type: %s\n",
+ sxe2_flow_engine_name[hw_flow->engine_type]);
+ cmdline_printf(cl, "\t\taction:");
+ for (i = 0; i < SXE2_FLOW_ACTION_MAX; i++) {
+ if (sxe2_test_bit(i, hw_flow->action.act_types))
+ cmdline_printf(cl, "%s ", sxe2_flow_action_name[i]);
+ }
+ cmdline_printf(cl, "\n");
+ }
+ }
+ cmdline_printf(cl, "Dump sxe2 flow rule end.\n");
+ ret = 0;
+l_end:
+ return ret;
+}
+
+static const char *tunnel_type_list[SXE2_UDP_TUNNEL_MAX] = {
+ [SXE2_UDP_TUNNEL_PROTOCOL_VXLAN] = "vxlan",
+ [SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE] = "vxlan-gpe",
+ [SXE2_UDP_TUNNEL_PROTOCOL_GENEVE] = "geneve",
+ [SXE2_UDP_TUNNEL_PROTOCOL_GTP_C] = "gtp-c",
+ [SXE2_UDP_TUNNEL_PROTOCOL_GTP_U] = "gtp-u",
+ [SXE2_UDP_TUNNEL_PROTOCOL_PFCP] = "pfcp",
+ [SXE2_UDP_TUNNEL_PROTOCOL_ECPRI] = "ecpri",
+ [SXE2_UDP_TUNNEL_PROTOCOL_MPLS] = "mpls",
+ [SXE2_UDP_TUNNEL_PROTOCOL_NVGRE] = "nvgre",
+ [SXE2_UDP_TUNNEL_PROTOCOL_L2TP] = "l2tp",
+ [SXE2_UDP_TUNNEL_PROTOCOL_TEREDO] = "teredo"
+};
+
+static enum sxe2_udp_tunnel_protocol sxe2_udp_tunnel_type_str2proto(const char *tunnel_type)
+{
+ enum sxe2_udp_tunnel_protocol proto;
+
+ for (proto = 0; proto < SXE2_UDP_TUNNEL_MAX; proto++) {
+ if (tunnel_type_list[proto] != NULL &&
+ strcmp(tunnel_type_list[proto], tunnel_type) == 0) {
+ break;
+ }
+ }
+
+ return proto;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_udp_tunnel_operations, 26.07)
+int32_t
+sxe2_udp_tunnel_operations(uint16_t port_id, struct cmdline *cl, uint8_t action,
+ uint16_t udp_port, const char *tunnel_type)
+{
+ enum sxe2_udp_tunnel_protocol proto = sxe2_udp_tunnel_type_str2proto(tunnel_type);
+ struct rte_eth_dev *dev = NULL;
+ struct sxe2_adapter *adapter = NULL;
+ struct sxe2_udp_tunnel_cfg tunnel_config = { 0 };
+ int32_t ret = -1;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (proto >= SXE2_UDP_TUNNEL_MAX) {
+ cmdline_printf(cl, "Invalid tunnel type!\n");
+ goto l_end;
+ }
+ adapter = dev->data->dev_private;
+ switch (action) {
+ case SXE2_TESTPMD_CMD_UDP_TUNNEL_ADD:
+ ret = sxe2_udp_tunnel_port_add_common(adapter, proto, udp_port);
+ break;
+ case SXE2_TESTPMD_CMD_UDP_TUNNEL_DEL:
+ ret = sxe2_udp_tunnel_port_del_common(adapter, proto, udp_port);
+ break;
+ case SXE2_TESTPMD_CMD_UDP_TUNNEL_GET:
+ tunnel_config.protocol = proto;
+ ret = sxe2_udp_tunnel_port_get_common(adapter, &tunnel_config);
+ if (!ret) {
+ cmdline_printf(cl, "Dump firmware udp tunnel config: [proto:%s, port:%d,"
+ "enable:%d, src/dst:%d/%d, used:%d]\n",
+ tunnel_type_list[proto], tunnel_config.fw_port,
+ tunnel_config.fw_status, tunnel_config.fw_src_en,
+ tunnel_config.fw_dst_en, tunnel_config.fw_used);
+ }
+ break;
+ default:
+ break;
+ }
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_stats_info_show, 26.07)
+int32_t
+sxe2_stats_info_show(uint16_t port_id)
+{
+ struct rte_eth_dev *dev = NULL;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int32_t sxe2_ipsec_init_mempools(void *sec_ctx)
+{
+ uint16_t nb_sess = 8192;
+ uint32_t sess_sz;
+ char s[64];
+ int32_t ret = -1;
+
+ sess_sz = rte_security_session_get_size(sec_ctx);
+ if (g_sess_pool == NULL) {
+ snprintf(s, sizeof(s), "sess_pool");
+ g_sess_pool = rte_mempool_create(s, nb_sess, sess_sz,
+ MEMPOOL_CACHE_SIZE, 0,
+ NULL, NULL, NULL, NULL,
+ SOCKET_ID_ANY, 0);
+ if (g_sess_pool == NULL) {
+ ret = -ENOMEM;
+ PMD_LOG_ERR(DRV, "Failed to malloc session pool memory.");
+ goto l_end;
+ }
+ }
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static void sxe2_ipsec_init_session_mgt(void)
+{
+ uint16_t i;
+ uint8_t port_id;
+
+ if (g_sxe2_ipsec_mgt_init)
+ return;
+
+ for (port_id = 0; port_id < SXE2_IPSEC_PORT_MAX; port_id++) {
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ g_tx_session[port_id][i].session = NULL;
+ g_tx_session[port_id][i].encrypt_algo = SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL;
+ g_tx_session[port_id][i].auth_algo = SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL;
+ g_tx_session[port_id][i].session_id = i;
+ g_tx_session[port_id][i].status = 0;
+ }
+ }
+
+ for (port_id = 0; port_id < SXE2_IPSEC_PORT_MAX; port_id++) {
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ g_rx_session[port_id][i].session = NULL;
+ g_rx_session[port_id][i].encrypt_algo = SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL;
+ g_rx_session[port_id][i].auth_algo = SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL;
+ g_rx_session[port_id][i].session_id = i;
+ g_rx_session[port_id][i].status = 0;
+ }
+ }
+
+ g_sxe2_ipsec_mgt_init = true;
+}
+
+static uint16_t sxe2_ipsec_session_mgt_alloc(enum sxe2_testpmd_ipsec_dir dir, uint16_t port_id)
+{
+ uint16_t i;
+ uint16_t index = 0XFFFF;
+ struct sxe2_ipsec_session_mgt *mgt = NULL;
+
+ if (dir == SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS)
+ mgt = g_tx_session[port_id];
+ else
+ mgt = g_rx_session[port_id];
+
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ if (mgt[i].status == 0) {
+ index = i;
+ mgt[i].status = 1;
+ break;
+ }
+ }
+
+ return index;
+}
+
+static void sxe2_ipsec_session_mgt_free(enum sxe2_testpmd_ipsec_dir dir,
+ uint16_t index, uint16_t port_id)
+{
+ struct sxe2_ipsec_session_mgt *mgt = NULL;
+
+ if (dir == SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS)
+ mgt = g_tx_session[port_id];
+ else
+ mgt = g_rx_session[port_id];
+
+ mgt[index].session = NULL;
+ mgt[index].status = 0;
+}
+
+static int32_t sxe2_ipsec_egress_construct(struct cmdline *cl,
+ struct rte_crypto_sym_xform **xform,
+ struct sxe2_ipsec_conf_param *param)
+{
+ struct rte_crypto_sym_xform *cur_xform = NULL;
+ struct rte_crypto_sym_xform *next_xform = NULL;
+ int32_t ret = -1;
+
+ cur_xform = rte_zmalloc("current xform",
+ sizeof(struct rte_crypto_sym_xform), 0);
+ if (cur_xform == NULL) {
+ ret = -ENOMEM;
+ cmdline_printf(cl, "Failed to malloc memory!\n");
+ goto l_end;
+ }
+ cur_xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ cur_xform->cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
+ if (param->encrypt_algo == SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC)
+ cur_xform->cipher.algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC;
+ else
+ cur_xform->cipher.algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC;
+ cur_xform->cipher.key.length = param->enc_len;
+ cur_xform->cipher.key.data = param->enc_key;
+
+ if (param->auth_algo == SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL) {
+ ret = 0;
+ goto l_end;
+ }
+
+ next_xform = rte_zmalloc("next xform",
+ sizeof(struct rte_crypto_sym_xform), 0);
+ if (next_xform == NULL) {
+ rte_free(cur_xform);
+ ret = -ENOMEM;
+ cmdline_printf(cl, "Failed to malloc memory!\n");
+ goto l_end;
+ }
+ next_xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
+ next_xform->auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
+ if (param->auth_algo == SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC)
+ next_xform->auth.algo = SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC;
+ else
+ next_xform->auth.algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC;
+ next_xform->auth.key.length = param->auth_len;
+ next_xform->auth.key.data = param->auth_key;
+ cur_xform->next = next_xform;
+ ret = 0;
+
+l_end:
+ *xform = cur_xform;
+ return ret;
+}
+
+static int32_t sxe2_ipsec_ingress_construct(struct cmdline *cl,
+ struct rte_crypto_sym_xform **xform,
+ struct sxe2_ipsec_conf_param *param)
+{
+ struct rte_crypto_sym_xform *cur_xform = NULL;
+ struct rte_crypto_sym_xform *next_xform = NULL;
+ int32_t ret = -1;
+
+ cur_xform = rte_zmalloc("current xform",
+ sizeof(struct rte_crypto_sym_xform), 0);
+ if (cur_xform == NULL) {
+ ret = -ENOMEM;
+ cmdline_printf(cl, "Failed to malloc memory!\n");
+ goto l_end;
+ }
+
+ if (param->auth_algo == SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL) {
+ cur_xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ cur_xform->cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+ if (param->encrypt_algo == SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC)
+ cur_xform->cipher.algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC;
+ else
+ cur_xform->cipher.algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC;
+ cur_xform->cipher.key.length = param->enc_len;
+ cur_xform->cipher.key.data = param->enc_key;
+ ret = 0;
+ goto l_end;
+ }
+
+ cur_xform->type = RTE_CRYPTO_SYM_XFORM_AUTH;
+ cur_xform->auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
+ if (param->auth_algo == SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC)
+ cur_xform->auth.algo = SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC;
+ else
+ cur_xform->auth.algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC;
+
+ cur_xform->auth.key.length = param->auth_len;
+ cur_xform->auth.key.data = param->auth_key;
+
+ next_xform = rte_zmalloc("next xform",
+ sizeof(struct rte_crypto_sym_xform), 0);
+ if (next_xform == NULL) {
+ rte_free(cur_xform);
+ ret = -ENOMEM;
+ cmdline_printf(cl, "Failed to malloc memory!\n");
+ goto l_end;
+ }
+
+ next_xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+ next_xform->cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+ if (param->encrypt_algo == SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC)
+ next_xform->cipher.algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC;
+ else
+ next_xform->cipher.algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC;
+ next_xform->cipher.key.length = param->enc_len;
+ next_xform->cipher.key.data = param->enc_key;
+ cur_xform->next = next_xform;
+ ret = 0;
+
+l_end:
+ *xform = cur_xform;
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_ingress_create, 26.07)
+int32_t
+sxe2_ipsec_ingress_create(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct rte_security_session_conf conf;
+ struct rte_crypto_sym_xform *encrypt_xform = NULL;
+ void *session = NULL;
+ struct rte_security_ctx *p_ctx = NULL;
+ int32_t ret = -1;
+ uint16_t index;
+ uint8_t i;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (dev->data->dev_started != 0) {
+ cmdline_printf(cl, "port %d must be stopped.\n", dev->data->port_id);
+ ret = 0;
+ goto l_end;
+ }
+
+ p_ctx = rte_eth_dev_get_sec_ctx(param->port_id);
+
+ if (g_sess_pool == NULL) {
+ ret = sxe2_ipsec_init_mempools(p_ctx);
+ if (ret)
+ goto l_end;
+ }
+
+ sxe2_ipsec_init_session_mgt();
+
+ memset(&conf, 0, sizeof(conf));
+ conf.protocol = RTE_SECURITY_PROTOCOL_IPSEC;
+ conf.action_type = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
+ conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+ conf.ipsec.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+ conf.ipsec.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
+ conf.ipsec.spi = param->spi;
+ conf.ipsec.udp.sport = param->sport;
+ conf.ipsec.udp.dport = param->dport;
+ conf.ipsec.tunnel.type = param->ip_addr.type;
+ if (param->sport || param->dport)
+ conf.ipsec.options.udp_encap = true;
+ if (param->ip_addr.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4)
+ conf.ipsec.tunnel.ipv4.dst_ip.s_addr = param->ip_addr.dst_ipv4;
+ else
+ memcpy(&conf.ipsec.tunnel.ipv6.dst_addr,
+ ¶m->ip_addr.dst_ipv6,
+ sizeof(param->ip_addr.dst_ipv6));
+
+ ret = sxe2_ipsec_ingress_construct(cl, &encrypt_xform, param);
+ if (ret)
+ goto l_end;
+ conf.crypto_xform = encrypt_xform;
+
+ session = rte_security_session_create(p_ctx, &conf, g_sess_pool);
+ if (session == NULL) {
+ ret = -1;
+ goto l_free;
+ }
+
+ index = sxe2_ipsec_session_mgt_alloc(param->dir, param->port_id);
+ if (index == 0XFFFF) {
+ ret = -1;
+ goto l_free;
+ }
+
+ g_rx_session[param->port_id][index].session = session;
+ g_rx_session[param->port_id][index].encrypt_algo = param->encrypt_algo;
+ g_rx_session[param->port_id][index].auth_algo = param->auth_algo;
+ for (i = 0; i < 32; i++) {
+ g_rx_session[param->port_id][index].enc_key[i] = param->enc_key[i];
+ g_rx_session[param->port_id][index].auth_key[i] = param->auth_key[i];
+ }
+ g_rx_session[param->port_id][index].sport = ntohs(param->sport);
+ g_rx_session[param->port_id][index].dport = ntohs(param->dport);
+ g_rx_session[param->port_id][index].spi = ntohl(param->spi);
+ memcpy(&g_rx_session[param->port_id][index].ip_addr,
+ ¶m->ip_addr,
+ sizeof(struct sxe2_ipsec_ip_param));
+
+ ret = 0;
+
+l_free:
+ if (encrypt_xform->next)
+ rte_free(encrypt_xform->next);
+ if (encrypt_xform)
+ rte_free(encrypt_xform);
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_ingress_destroy, 26.07)
+int32_t
+sxe2_ipsec_ingress_destroy(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct rte_security_ctx *p_ctx = NULL;
+ struct rte_security_session *session = NULL;
+ int32_t ret = -1;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ cmdline_printf(cl, "Invalid dev.\n");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (dev->data->dev_started != 0) {
+ cmdline_printf(cl, "port %d must be stopped.\n", dev->data->port_id);
+ ret = 0;
+ goto l_end;
+ }
+
+ if (param->session_id >= SXE2_IPSEC_SESSION_MAX) {
+ PMD_LOG_ERR(DRV, "Invalid session id.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!g_rx_session[param->port_id][param->session_id].status) {
+ PMD_LOG_ERR(DRV, "Invalid session status.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (g_rx_session[param->port_id][param->session_id].session == NULL) {
+ PMD_LOG_ERR(DRV, "Invalid session data.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ p_ctx = rte_eth_dev_get_sec_ctx(param->port_id);
+
+ session = g_rx_session[param->port_id][param->session_id].session;
+ ret = rte_security_session_destroy(p_ctx, session);
+ if (ret)
+ goto l_end;
+ sxe2_ipsec_session_mgt_free(param->dir, param->session_id, param->port_id);
+
+ ret = 0;
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_ingress_show, 26.07)
+int32_t
+sxe2_ipsec_ingress_show(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ int32_t ret = -1;
+ uint16_t i;
+ uint8_t j;
+ char encrypt_key[65];
+ char auth_key[65];
+ const char *encrypt_algo[SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC] = "aes-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_SM4_CBC] = "sm4-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL] = "null"
+ };
+
+ const char *auth_algo[SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC] = "sha-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SM3_HMAC] = "sm3-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL] = "null"
+ };
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ if (g_rx_session[param->port_id][i].status &&
+ g_rx_session[param->port_id][i].session) {
+ memset(encrypt_key, '\0', sizeof(encrypt_key));
+ memset(auth_key, '\0', sizeof(auth_key));
+ for (j = 0; j < 32; j++) {
+ sprintf(encrypt_key + 2 * j, "%02x",
+ g_rx_session[param->port_id][i].enc_key[j]);
+ }
+
+ if (g_rx_session[param->port_id][i].auth_algo !=
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL) {
+ for (j = 0; j < 32; j++) {
+ sprintf(auth_key + 2 * j, "%02x",
+ g_rx_session[param->port_id][i].auth_key[j]);
+ }
+ }
+
+ cmdline_printf(cl, "session_id:%u, direction:rx ,"
+ "encrypt_algo:%s, encrypt_key:0x%s,"
+ "auth_algo:%s, auth_key:0x%s, sport:%u, dport:%u, spi:%u\n",
+ i,
+ encrypt_algo[g_rx_session[param->port_id][i].encrypt_algo],
+ encrypt_key,
+ auth_algo[g_rx_session[param->port_id][i].auth_algo],
+ auth_key,
+ g_rx_session[param->port_id][i].sport,
+ g_rx_session[param->port_id][i].dport,
+ g_rx_session[param->port_id][i].spi);
+ }
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_egress_create, 26.07)
+int32_t
+sxe2_ipsec_egress_create(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct rte_security_session_conf conf;
+ struct rte_crypto_sym_xform *encrypt_xform = NULL;
+ void *session = NULL;
+ struct rte_security_ctx *p_ctx = NULL;
+ int32_t ret = -1;
+ uint16_t index;
+ uint8_t i;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (dev->data->dev_started != 0) {
+ cmdline_printf(cl, "port %d must be stopped.\n", dev->data->port_id);
+ ret = 0;
+ goto l_end;
+ }
+
+ p_ctx = rte_eth_dev_get_sec_ctx(param->port_id);
+
+ if (g_sess_pool == NULL) {
+ ret = sxe2_ipsec_init_mempools(p_ctx);
+ if (ret)
+ goto l_end;
+ }
+
+ sxe2_ipsec_init_session_mgt();
+
+ memset(&conf, 0, sizeof(conf));
+ conf.protocol = RTE_SECURITY_PROTOCOL_IPSEC;
+ conf.action_type = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
+ conf.ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+ conf.ipsec.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+ conf.ipsec.direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS;
+
+ ret = sxe2_ipsec_egress_construct(cl, &encrypt_xform, param);
+ if (ret)
+ goto l_end;
+ conf.crypto_xform = encrypt_xform;
+
+ session = rte_security_session_create(p_ctx, &conf, g_sess_pool);
+ if (session == NULL) {
+ ret = -1;
+ goto l_free;
+ }
+
+ index = sxe2_ipsec_session_mgt_alloc(param->dir, param->port_id);
+ if (index == 0XFFFF) {
+ ret = -1;
+ goto l_free;
+ }
+
+ g_tx_session[param->port_id][index].session = session;
+ g_tx_session[param->port_id][index].encrypt_algo = param->encrypt_algo;
+ g_tx_session[param->port_id][index].auth_algo = param->auth_algo;
+ for (i = 0; i < 32; i++) {
+ g_tx_session[param->port_id][index].enc_key[i] = param->enc_key[i];
+ g_tx_session[param->port_id][index].auth_key[i] = param->auth_key[i];
+ }
+ ret = 0;
+
+l_free:
+ if (encrypt_xform->next)
+ rte_free(encrypt_xform->next);
+ if (encrypt_xform)
+ rte_free(encrypt_xform);
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_egress_destroy, 26.07)
+int32_t
+sxe2_ipsec_egress_destroy(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct rte_security_ctx *p_ctx = NULL;
+ struct rte_security_session *session = NULL;
+ int32_t ret = -1;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (dev->data->dev_started != 0) {
+ cmdline_printf(cl, "port %d must be stopped.\n", dev->data->port_id);
+ ret = 0;
+ goto l_end;
+ }
+
+ if (param->session_id >= SXE2_IPSEC_SESSION_MAX) {
+ PMD_LOG_ERR(DRV, "Invalid session id.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!g_tx_session[param->port_id][param->session_id].status) {
+ PMD_LOG_ERR(DRV, "Invalid session status.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (g_tx_session[param->port_id][param->session_id].session == NULL) {
+ PMD_LOG_ERR(DRV, "Invalid session data.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ p_ctx = rte_eth_dev_get_sec_ctx(param->port_id);
+
+ session = g_tx_session[param->port_id][param->session_id].session;
+ ret = rte_security_session_destroy(p_ctx, session);
+ if (ret)
+ goto l_end;
+ sxe2_ipsec_session_mgt_free(param->dir, param->session_id, param->port_id);
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_egress_show, 26.07)
+int32_t
+sxe2_ipsec_egress_show(struct sxe2_ipsec_conf_param *param, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ int32_t ret = -1;
+ uint16_t i;
+ uint8_t j;
+ char encrypt_key[65];
+ char auth_key[65];
+ const char *encrypt_algo[SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC] = "aes-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_SM4_CBC] = "sm4-cbc",
+ [SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL] = "null"
+ };
+
+ const char *auth_algo[SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX] = {
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC] = "sha-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SM3_HMAC] = "sm3-hmac",
+ [SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL] = "null"
+ };
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(param->port_id, -ENODEV);
+
+ dev = &rte_eth_devices[param->port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ if (g_tx_session[param->port_id][i].status &&
+ g_tx_session[param->port_id][i].session) {
+ memset(encrypt_key, '\0', sizeof(encrypt_key));
+ memset(auth_key, '\0', sizeof(auth_key));
+ for (j = 0; j < 32; j++)
+ sprintf(encrypt_key + 2 * j, "%02x",
+ g_tx_session[param->port_id][i].enc_key[j]);
+ if (g_tx_session[param->port_id][i].auth_algo !=
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL)
+ for (j = 0; j < 32; j++)
+ sprintf(auth_key + 2 * j, "%02x",
+ g_tx_session[param->port_id][i].auth_key[j]);
+
+ cmdline_printf(cl, "id:%u, tx , encrypt_algo:%s,"
+ "encrypt_key:0x%s, auth_algo:%s, auth_key:0x%s.\n",
+ i,
+ encrypt_algo[g_tx_session[param->port_id][i].encrypt_algo],
+ encrypt_key,
+ auth_algo[g_tx_session[param->port_id][i].auth_algo],
+ auth_key);
+ }
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_conf_get, 26.07)
+int32_t
+sxe2_ipsec_conf_get(uint16_t port_id, struct cmdline *cl, char type[])
+{
+ struct rte_eth_dev *dev = NULL;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ return -ENODEV;
+ }
+ if (!strcmp(type, "session-id"))
+ cmdline_printf(cl, "session-id: %u\n",
+ g_tx_sess_id[port_id]);
+ else if (!strcmp(type, "esp-hdr-offset"))
+ cmdline_printf(cl, "esp-hdr-offset: %u\n",
+ g_esp_header_offset[port_id]);
+ else
+ cmdline_printf(cl, "Invalid type: %s\n", type);
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_conf_set, 26.07)
+int32_t
+sxe2_ipsec_conf_set(uint16_t port_id, struct cmdline *cl, char type[], uint16_t value)
+{
+ struct rte_eth_dev *dev = NULL;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ PMD_LOG_ERR(DRV, "Invalid dev.");
+ return -ENODEV;
+ }
+ if (!strcmp(type, "session-id")) {
+ if (value >= 4096 || !g_tx_session[port_id][value].status) {
+ cmdline_printf(cl, "Invalid session-id: %u,"
+ "0 <= value <= 4095 or the session is inactive.\n", value);
+ return -EINVAL;
+ }
+ g_tx_sess_id[port_id] = value;
+ cmdline_printf(cl, "session-id: %u\n", g_tx_sess_id[port_id]);
+ } else if (!strcmp(type, "esp-hdr-offset")) {
+ if (value < 34 || value > 512) {
+ cmdline_printf(cl, "Invalid esp-hdr-offset: %u,"
+ "34 <= value <= 512.\n", value);
+ return -EINVAL;
+ }
+ g_esp_header_offset[port_id] = value;
+ cmdline_printf(cl, "esp-hdr-offset: %u\n",
+ g_esp_header_offset[port_id]);
+ } else {
+ cmdline_printf(cl, "Invalid type: %s\n", type);
+ }
+
+ return 0;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_stats_show, 26.07)
+int32_t
+sxe2_ipsec_stats_show(uint16_t port_id)
+{
+ (void)port_id;
+ return 0;
+}
+
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(sxe2_ipsec_flush, 26.07)
+int32_t
+sxe2_ipsec_flush(uint16_t port_id, struct cmdline *cl)
+{
+ struct rte_eth_dev *dev = NULL;
+ struct rte_security_ctx *p_ctx = NULL;
+ struct rte_security_session *session = NULL;
+ int32_t ret = -1;
+ uint16_t i;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+
+ dev = &rte_eth_devices[port_id];
+ if (!sxe2_is_supported(dev)) {
+ cmdline_printf(cl, "Invalid dev.\n");
+ ret = -ENODEV;
+ goto l_end;
+ }
+
+ if (dev->data->dev_started != 0) {
+ cmdline_printf(cl, "port %d must be stopped.\n", dev->data->port_id);
+ ret = 0;
+ goto l_end;
+ }
+
+ p_ctx = rte_eth_dev_get_sec_ctx(port_id);
+
+ g_esp_header_offset[port_id] = 0;
+ g_tx_sess_id[port_id] = 0;
+
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ session = g_tx_session[port_id][i].session;
+ if (g_tx_session[port_id][i].status && session) {
+ ret = rte_security_session_destroy(p_ctx, session);
+ if (ret)
+ cmdline_printf(cl, "failed to destroy tx session: %d.\n", i);
+ else
+ sxe2_ipsec_session_mgt_free(SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS,
+ i, port_id);
+ }
+ }
+
+ for (i = 0; i < SXE2_IPSEC_SESSION_MAX; i++) {
+ session = g_rx_session[port_id][i].session;
+ if (g_rx_session[port_id][i].status && session) {
+ ret = rte_security_session_destroy(p_ctx, session);
+ if (ret)
+ cmdline_printf(cl, "failed to destroy rx session: %d.\n", i);
+ else
+ sxe2_ipsec_session_mgt_free(SXE2_TESTPMD_CMD_IPSEC_DIR_INGRESS,
+ i, port_id);
+ }
+ }
+
+ g_sxe2_ipsec_mgt_init = false;
+ ret = 0;
+
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_testpmd_lib.h b/drivers/net/sxe2/sxe2_testpmd_lib.h
new file mode 100644
index 0000000000..3d2659ef00
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_testpmd_lib.h
@@ -0,0 +1,142 @@
+
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_TESTPMD_LIB_H__
+#define __SXE2_TESTPMD_LIB_H__
+#include <cmdline.h>
+#include "sxe2_ipsec.h"
+
+#define SXE2_IPSEC_SESSION_MAX (4096)
+#define SXE2_IPSEC_PORT_MAX RTE_MAX_ETHPORTS
+#define MEMPOOL_CACHE_SIZE (512 / 2)
+
+enum {
+ SXE2_TESTPMD_CMD_UDP_TUNNEL_ADD = 0,
+ SXE2_TESTPMD_CMD_UDP_TUNNEL_DEL = 1,
+ SXE2_TESTPMD_CMD_UDP_TUNNEL_GET = 2,
+ SXE2_TESTPMD_CMD_UDP_TUNNEL_MAX,
+};
+
+enum sxe2_testpmd_ipsec_op {
+ SXE2_TESTPMD_CMD_IPSEC_OP_ADD = 0,
+ SXE2_TESTPMD_CMD_IPSEC_OP_RM = 1,
+ SXE2_TESTPMD_CMD_IPSEC_OP_SHOW = 2,
+ SXE2_TESTPMD_CMD_IPSEC_OP_MAX,
+};
+
+enum sxe2_testpmd_ipsec_dir {
+ SXE2_TESTPMD_CMD_IPSEC_DIR_EGRESS = 0,
+ SXE2_TESTPMD_CMD_IPSEC_DIR_INGRESS = 1,
+ SXE2_TESTPMD_CMD_IPSEC_DIR_MAX,
+};
+
+enum sxe2_testpmd_ipsec_encrypt_algo {
+ SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_AES_CBC = 0,
+ SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_SM4_CBC = 1,
+ SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_NULL = 2,
+ SXE2_TESTPMD_CMD_IPSEC_EN_ALGO_MAX,
+};
+
+enum sxe2_testpmd_ipsec_auth_algo {
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SHA_HMAC = 0,
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_SM3_HMAC = 1,
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_NULL = 2,
+ SXE2_TESTPMD_CMD_IPSEC_AUTH_ALGO_MAX,
+};
+
+struct sxe2_ipsec_conf_param {
+ enum sxe2_testpmd_ipsec_dir dir;
+ enum sxe2_testpmd_ipsec_op op;
+ enum sxe2_testpmd_ipsec_encrypt_algo encrypt_algo;
+ enum sxe2_testpmd_ipsec_auth_algo auth_algo;
+ struct sxe2_ipsec_ip_param ip_addr;
+ uint32_t spi;
+ uint16_t port_id;
+ uint16_t session_id;
+ uint16_t sport;
+ uint16_t dport;
+ uint8_t enc_key[32];
+ uint8_t enc_len;
+ uint8_t auth_key[32];
+ uint8_t auth_len;
+};
+
+struct sxe2_ipsec_session_mgt {
+ void *session;
+ enum sxe2_testpmd_ipsec_encrypt_algo encrypt_algo;
+ enum sxe2_testpmd_ipsec_auth_algo auth_algo;
+ struct sxe2_ipsec_ip_param ip_addr;
+ uint32_t spi;
+ uint16_t session_id;
+ uint16_t sport;
+ uint16_t dport;
+ uint8_t enc_key[32];
+ uint8_t auth_key[32];
+ uint8_t status;
+};
+
+__rte_experimental
+int32_t
+sxe2_testpmd_sched_reset(uint16_t port_id);
+
+__rte_experimental
+int32_t
+sxe2_flow_rule_dump(uint16_t port_id, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_udp_tunnel_operations(uint16_t port_id, struct cmdline *cl, uint8_t action,
+ uint16_t udp_port, const char *tunnel_type);
+
+__rte_experimental
+int32_t
+sxe2_stats_info_show(uint16_t port_id);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_ingress_create(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_ingress_destroy(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_ingress_show(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_egress_create(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_egress_destroy(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_egress_show(struct sxe2_ipsec_conf_param *param, struct cmdline *cl);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_conf_get(uint16_t port_id, struct cmdline *cl, char type[]);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_conf_set(uint16_t port_id, struct cmdline *cl, char type[], uint16_t value);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_stats_show(uint16_t port_id);
+
+__rte_experimental
+int32_t
+sxe2_ipsec_flush(uint16_t port_id, struct cmdline *cl);
+
+extern struct sxe2_ipsec_session_mgt g_tx_session[SXE2_IPSEC_PORT_MAX][SXE2_IPSEC_SESSION_MAX];
+extern uint16_t g_tx_sess_id[SXE2_IPSEC_PORT_MAX];
+extern uint16_t g_esp_header_offset[SXE2_IPSEC_PORT_MAX];
+extern struct rte_mempool *g_sess_pool;
+
+#endif /* __SXE2_TESTPMD_LIB_H__ */
diff --git a/drivers/net/sxe2/sxe2_tm.c b/drivers/net/sxe2/sxe2_tm.c
index 4c4f793cd5..5de9b5d3b7 100644
--- a/drivers/net/sxe2/sxe2_tm.c
+++ b/drivers/net/sxe2/sxe2_tm.c
@@ -982,6 +982,24 @@ int32_t sxe2_tm_init(struct rte_eth_dev *dev)
return ret;
}
+int32_t sxe2_tm_conf_reset(struct rte_eth_dev *dev)
+{
+ int32_t ret;
+
+ ret = sxe2_tm_uninit(dev);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_tm_init(dev);
+ if (ret)
+ goto l_end;
+
+ PMD_LOG_DEBUG(DRV, "Tm config reset succeed.");
+
+l_end:
+ return ret;
+}
+
static int32_t sxe2_tm_chk_all_leaf(struct rte_eth_dev *dev)
{
int32_t ret = 0;
diff --git a/drivers/net/sxe2/sxe2_tm.h b/drivers/net/sxe2/sxe2_tm.h
index c4f8da6a8e..b0bfc2091d 100644
--- a/drivers/net/sxe2/sxe2_tm.h
+++ b/drivers/net/sxe2/sxe2_tm.h
@@ -73,4 +73,6 @@ int32_t sxe2_tm_init(struct rte_eth_dev *dev);
int32_t sxe2_tm_uninit(struct rte_eth_dev *dev);
+int32_t sxe2_tm_conf_reset(struct rte_eth_dev *dev);
+
#endif /* __SXE2_TM_H__ */
--
2.52.0
^ permalink raw reply related
* [PATCH v14 16/20] net/sxe2: support SFP module info and EEPROM access
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch implements 'get_module_info' and 'get_module_eeprom'
ops for the sxe2 PMD. These interfaces allow applications to retrieve
the type of the plugged-in optical module and read its internal
EEPROM data.
The implementation utilizes the shared SFP header definitions to
parse the module ID, connector type, and encoding. It supports
reading the standard 256-byte EEPROM maps (SFF-8472 for SFP and
SFF-8636 for QSFP) via hardware-specific access commands.
Key features:
- Identify module types (SFP/SFP+/QSFP/QSFP28).
- Support standard EEPROM data retrieval for diagnostic tools.
- Add boundary checks to ensure safe I2C memory access.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/sxe2_cmd_chnl.c | 46 +++++
drivers/net/sxe2/sxe2_cmd_chnl.h | 3 +
drivers/net/sxe2/sxe2_drv_cmd.h | 18 ++
drivers/net/sxe2/sxe2_ethdev.c | 298 +++++++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_ethdev.h | 9 +
5 files changed, 374 insertions(+)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 926eaee062..43e8c59487 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -1833,3 +1833,49 @@ int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
return ret;
}
+
+int32_t sxe2_drv_sfp_eeprom_read(struct sxe2_adapter *adapter, struct sxe2_sfp_read_info *sfp_info)
+{
+ int32_t ret = -1;
+ struct sxe2_drv_sfp_req req = {0};
+ struct sxe2_drv_sfp_resp *resp = NULL;
+ struct sxe2_drv_cmd_params cmd = {0};
+
+ resp = rte_zmalloc("read sfp data", sizeof(*resp) + sfp_info->len, 0);
+ if (!resp) {
+ PMD_LOG_ERR(DRV, "Alloc memory failed");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ req.is_wr = false;
+ req.is_qsfp = sfp_info->is_qsfp;
+ req.page_cnt = rte_cpu_to_le_16(sfp_info->page_cnt);
+ req.offset = rte_cpu_to_le_16(sfp_info->offset);
+ req.data_len = rte_cpu_to_le_16(sfp_info->len);
+ req.bus_addr = rte_cpu_to_le_16(sfp_info->bus_addr);
+
+ PMD_DEV_LOG_INFO(adapter, DRV, "is_qsfp=%u, page_cnt=%u, offset=%u, datalen=%u, "
+ "bus_addr=%u", sfp_info->is_qsfp, sfp_info->page_cnt, sfp_info->offset,
+ sfp_info->len, sfp_info->bus_addr);
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_OPT_EEP_GET,
+ &req, sizeof(req),
+ resp, sizeof(*resp) + sfp_info->len);
+ ret = sxe2_drv_cmd_exec(adapter->cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to read sfp, ret=%d", ret);
+ goto l_end;
+ }
+
+ ret = 0;
+ rte_memcpy(sfp_info->data, resp->data, sfp_info->len);
+
+l_end:
+ if (resp) {
+ rte_free(resp);
+ resp = NULL;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 97007c7cfa..988d4b458b 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -167,4 +167,7 @@ int32_t sxe2_drv_flow_fnav_query_stat(struct sxe2_adapter *adapter,
int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
uint16_t *vsi_list, uint16_t vsi_cnt, bool set);
+int32_t sxe2_drv_sfp_eeprom_read(struct sxe2_adapter *adapter,
+ struct sxe2_sfp_read_info *sfp_info);
+
#endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index f7acd20642..09b2f7d125 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -633,6 +633,24 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_udp_tunnel_resp {
uint8_t rsv;
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_sfp_req {
+ uint8_t is_wr;
+ uint8_t is_qsfp;
+ uint16_t bus_addr;
+ uint16_t page_cnt;
+ uint16_t offset;
+ uint16_t data_len;
+ uint16_t rvd;
+ uint8_t data[];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_sfp_resp {
+ uint8_t is_wr;
+ uint8_t is_qsfp;
+ uint16_t data_len;
+ uint8_t data[];
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index d1ced7d427..d2b884c6cd 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -41,6 +41,7 @@
#include "sxe2_ethdev_repr.h"
#include "sxe2vf_regs.h"
#include "sxe2_switchdev.h"
+#include "sxe2_msg.h"
#define SXE2_PCI_VENDOR_ID_1 0x1ff2
#define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
@@ -122,6 +123,10 @@ static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *tunnel_udp);
static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev,
char *fw_version, size_t fw_size);
+static int32_t sxe2_get_module_info(struct rte_eth_dev *dev,
+ struct rte_eth_dev_module_info *info);
+static int32_t sxe2_get_module_eeprom(struct rte_eth_dev *dev,
+ struct rte_dev_eeprom_info *info);
static const struct eth_dev_ops sxe2_eth_dev_ops = {
.dev_configure = sxe2_dev_configure,
@@ -186,6 +191,9 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.fw_version_get = sxe2_fw_version_string_get,
.get_monitor_addr = sxe2_get_monitor_addr,
+
+ .get_module_info = sxe2_get_module_info,
+ .get_module_eeprom = sxe2_get_module_eeprom,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -291,6 +299,296 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
return ret;
}
+static int32_t sxe2_sfp_type_get(struct sxe2_adapter *adapter, uint8_t *type)
+{
+ int32_t ret = -1;
+ struct sxe2_sfp_read_info sfp_info;
+
+ memset(&sfp_info, 0, sizeof(sfp_info));
+ sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0;
+ sfp_info.len = 1;
+ sfp_info.data = type;
+ sfp_info.offset = 0;
+ sfp_info.page_cnt = 0;
+ sfp_info.is_qsfp = false;
+
+ ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info);
+ if (ret)
+ goto l_end;
+
+ ret = 0;
+ PMD_LOG_INFO(DRV, "Get sfp type success, type=%u", *type);
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_sfp_module_info_get(struct sxe2_adapter *adapter,
+ struct rte_eth_dev_module_info *info)
+{
+ int32_t ret = -1;
+ bool page_swap = false;
+ uint8_t sff8472_rev = 0;
+ uint8_t addr_mode = 0;
+ struct sxe2_sfp_read_info sfp_info;
+
+ memset(&sfp_info, 0, sizeof(sfp_info));
+ sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0;
+ sfp_info.is_qsfp = false;
+ sfp_info.len = 1;
+ sfp_info.data = &sff8472_rev;
+ sfp_info.offset = SXE2_MODULE_SFF_8472_COMP;
+ sfp_info.page_cnt = 0;
+
+ ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to read 8472 protocol, ret=%d", ret);
+ goto l_end;
+ }
+
+ sfp_info.data = &addr_mode;
+ sfp_info.offset = SXE2_MODULE_SFF_8472_SWAP;
+
+ ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to read A2 page, ret=%d", ret);
+ goto l_end;
+ }
+
+ if (addr_mode & SXE2_MODULE_SFF_ADDR_MODE) {
+ PMD_LOG_ERR(DRV, "address change required to access page 0xA2, "
+ "but not supported. please report the module "
+ "type to the driver maintainers.");
+ page_swap = true;
+ }
+
+ PMD_LOG_INFO(DRV, "Read sfp module info, sff_8472=%u, a2_page=%u, swap_page=%d",
+ sff8472_rev, addr_mode, page_swap);
+
+ if (sff8472_rev == SXE2_MODULE_SFF_8472_UNSUP ||
+ page_swap ||
+ !(addr_mode & SXE2_MODULE_SFF_DDM_IMPLEMENTED)) {
+ info->type = SXE2_MODULE_SFF_8079;
+ info->eeprom_len = SXE2_MODULE_SFF_8079_LEN;
+ } else {
+ info->type = SXE2_MODULE_SFF_8472;
+ info->eeprom_len = SXE2_MODULE_SFF_8472_LEN;
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_qsfp_module_info_get(struct sxe2_adapter *adapter, struct rte_eth_dev_module_info *info)
+{
+ int32_t ret = -1;
+ uint8_t sff8636_rev = 0;
+ struct sxe2_sfp_read_info sfp_info;
+
+ memset(&sfp_info, 0, sizeof(sfp_info));
+ sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0;
+ sfp_info.is_qsfp = true;
+ sfp_info.len = 1;
+ sfp_info.data = &sff8636_rev;
+ sfp_info.offset = SXE2_MODULE_REVISION_ADDR;
+ sfp_info.page_cnt = 0;
+
+ ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to read 8636 protocol, ret=%d", ret);
+ goto l_end;
+ }
+
+ if (sff8636_rev > 0x02) {
+ info->type = SXE2_MODULE_SFF_8636;
+ info->eeprom_len = SXE2_MODULE_SFF_8636_MAX_LEN;
+ } else {
+ info->type = SXE2_MODULE_SFF_8436;
+ info->eeprom_len = SXE2_MODULE_SFF_8436_MAX_LEN;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_get_module_info(struct rte_eth_dev *dev, struct rte_eth_dev_module_info *info)
+{
+ int32_t ret = -1;
+ uint8_t type = 0;
+ struct sxe2_adapter *adapter = dev->data->dev_private;
+
+ ret = sxe2_sfp_type_get(adapter, &type);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to read sfp type, ret=%d", ret);
+ goto l_end;
+ }
+
+ switch (type) {
+ case SXE2_MODULE_SFF_SFP_TYPE:
+ ret = sxe2_sfp_module_info_get(adapter, info);
+ if (ret)
+ goto l_end;
+ break;
+ case SXE2_MODULE_TYPE_QSFP_PLUS:
+ case SXE2_MODULE_TYPE_QSFP28:
+ ret = sxe2_qsfp_module_info_get(adapter, info);
+ if (ret)
+ goto l_end;
+ break;
+ default:
+ ret = -ENXIO;
+ PMD_LOG_ERR(DRV, "Invalid sfp type, type=%d.", type);
+ goto l_end;
+ }
+
+ PMD_LOG_INFO(DRV, "sfp eeprom type=%x, eeprom len=%d.", info->type, info->eeprom_len);
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_get_sfp_eeprom(struct sxe2_adapter *adapter, struct sxe2_sfp_read_info *sfp_info)
+{
+ int32_t ret = -1;
+ uint16_t ori_len = sfp_info->len;
+ uint16_t ori_offset = sfp_info->offset;
+
+ if ((ori_len + ori_offset) > SXE2_SFP_EEP_LEN_MAX) {
+ sfp_info->len = (uint16_t)(SXE2_SFP_EEP_LEN_MAX - ori_offset);
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ if (ret)
+ goto l_end;
+ sfp_info->bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR1;
+ sfp_info->len = (uint16_t)(ori_len - (SXE2_SFP_EEP_LEN_MAX - ori_offset));
+ sfp_info->data = (uint8_t *)(sfp_info->data) + (SXE2_SFP_EEP_LEN_MAX - ori_offset);
+ sfp_info->offset = 0;
+ sfp_info->page_cnt = 0;
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ } else {
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ }
+
+l_end:
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to read sfp.");
+ return ret;
+}
+
+static int32_t
+sxe2_get_qsfp_eeprom(struct sxe2_adapter *adapter,
+ struct sxe2_sfp_read_info *sfp_info)
+{
+ int32_t ret = -1;
+ uint16_t ori_len = sfp_info->len;
+ uint16_t ori_offset = sfp_info->offset;
+ uint16_t read_len = 0;
+ uint16_t remain_len = 0;
+
+ if ((ori_len + ori_offset) > SXE2_SFP_EEP_LEN_MAX) {
+ sfp_info->len = (uint16_t)(SXE2_SFP_EEP_LEN_MAX - ori_offset);
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ if (ret)
+ goto l_end;
+
+ do {
+ read_len = read_len + sfp_info->len;
+ sfp_info->data = (uint8_t *)(sfp_info->data) + sfp_info->len;
+ sfp_info->offset = SXE2_QSFP_PAGE_OFST_START;
+ sfp_info->page_cnt++;
+ remain_len = (uint16_t)(ori_len - read_len);
+ sfp_info->len = (remain_len > SXE2_QSFP_PAGE_OFST_START) ?
+ SXE2_QSFP_PAGE_OFST_START : remain_len;
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ if (ret)
+ goto l_end;
+ } while (remain_len > SXE2_QSFP_PAGE_OFST_START);
+ } else {
+ ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info);
+ }
+
+l_end:
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to read sfp.");
+ return ret;
+}
+
+static int32_t
+sxe2_get_module_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *info)
+{
+ int32_t ret = -1;
+ uint8_t type = 0;
+ struct sxe2_adapter *adapter = dev->data->dev_private;
+ struct sxe2_sfp_read_info sfp_info;
+
+ memset(&sfp_info, 0, sizeof(sfp_info));
+
+ if (!info || !info->length || !info->data ||
+ info->offset >= SXE2_SFP_EEP_LEN_MAX) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ PMD_LOG_INFO(DRV, "Dump sfp eeprom info offset=0x%x, len=0x%x.",
+ info->offset, info->length);
+
+ ret = sxe2_sfp_type_get(adapter, &type);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to read sfp type, ret=%d", ret);
+ goto l_end;
+ }
+
+ sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0;
+ sfp_info.len = info->length;
+ sfp_info.data = info->data;
+ sfp_info.offset = info->offset;
+ sfp_info.page_cnt = 0;
+
+ switch (type) {
+ case SXE2_MODULE_SFF_SFP_TYPE:
+ if (info->length > SXE2_SFP_EEP_LEN_MAX * 2) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "sfp read size[%u] > eeprom max size[%d], ret=%d",
+ info->length, SXE2_SFP_EEP_LEN_MAX * 2, ret);
+ goto l_end;
+ }
+ sfp_info.is_qsfp = false;
+ ret = sxe2_get_sfp_eeprom(adapter, &sfp_info);
+ if (ret)
+ goto l_end;
+ break;
+ case SXE2_MODULE_TYPE_QSFP_PLUS:
+ case SXE2_MODULE_TYPE_QSFP28:
+ if (info->length > SXE2_MODULE_SFF_8636_MAX_LEN) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "sfp read size[%u] > eeprom max size[%d], ret=%d",
+ info->length, SXE2_SFP_EEP_LEN_MAX * 2, ret);
+ goto l_end;
+ }
+ sfp_info.is_qsfp = true;
+ ret = sxe2_get_qsfp_eeprom(adapter, &sfp_info);
+ if (ret)
+ goto l_end;
+ break;
+ default:
+ ret = -ENXIO;
+ PMD_LOG_ERR(DRV, "Invalid sfp type, type=%d.", type);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
static enum sxe2_udp_tunnel_protocol
sxe2_udp_tunnel_type_rte_to_sxe2(enum rte_eth_tunnel_type rte_type)
{
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 34f9aa46b2..510f5139c3 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -275,6 +275,15 @@ struct sxe2_sched_hw_cap {
uint8_t adj_lvl;
};
+struct sxe2_sfp_read_info {
+ uint8_t *data;
+ uint16_t offset;
+ uint16_t len;
+ uint16_t bus_addr;
+ uint16_t page_cnt;
+ bool is_qsfp;
+};
+
struct sxe2_link_context {
rte_spinlock_t link_lock;
bool link_up;
--
2.52.0
^ permalink raw reply related
* [PATCH v14 11/20] drivers: add support for VF representors
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
Add support for VF representors in sxe2 PMD. This allows the host
application (e.g., OVS-DPDK) to control and monitor virtual functions
through a dedicated ethdev on the PF (Physical Function) side.
Key changes include:
- Added representor enumeration and identification logic.
- Implemented representor-specific dev_ops (link update, stats, etc.).
- Configured back-channel communication between PF and VF for control
messages.
- Supported the "-a <DBDF>,representor=[0-N]" EAL parameter to
instantiate representor ports.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/common/sxe2/sxe2_common.c | 46 +
drivers/common/sxe2/sxe2_common.h | 2 +
drivers/net/sxe2/meson.build | 6 +
drivers/net/sxe2/sxe2_cmd_chnl.c | 311 +++-
drivers/net/sxe2/sxe2_cmd_chnl.h | 28 +
drivers/net/sxe2/sxe2_drv_cmd.h | 55 +-
drivers/net/sxe2/sxe2_ethdev.c | 201 ++-
drivers/net/sxe2/sxe2_ethdev.h | 11 +
drivers/net/sxe2/sxe2_ethdev_repr.c | 607 +++++++
drivers/net/sxe2/sxe2_ethdev_repr.h | 32 +
drivers/net/sxe2/sxe2_filter.c | 121 +-
drivers/net/sxe2/sxe2_filter.h | 2 +
drivers/net/sxe2/sxe2_flow.c | 1337 ++++++++++++++
drivers/net/sxe2/sxe2_flow.h | 29 +
drivers/net/sxe2/sxe2_flow_parse_action.c | 1182 +++++++++++++
drivers/net/sxe2/sxe2_flow_parse_action.h | 23 +
drivers/net/sxe2/sxe2_flow_parse_engine.c | 106 ++
drivers/net/sxe2/sxe2_flow_parse_engine.h | 13 +
drivers/net/sxe2/sxe2_flow_parse_pattern.c | 1822 ++++++++++++++++++++
drivers/net/sxe2/sxe2_flow_parse_pattern.h | 40 +
drivers/net/sxe2/sxe2_irq.c | 54 +
drivers/net/sxe2/sxe2_irq.h | 4 +
drivers/net/sxe2/sxe2_queue.c | 6 +-
drivers/net/sxe2/sxe2_stats.c | 17 +-
drivers/net/sxe2/sxe2_switchdev.c | 332 ++++
drivers/net/sxe2/sxe2_switchdev.h | 33 +
drivers/net/sxe2/sxe2_txrx.c | 7 +
drivers/net/sxe2/sxe2_txrx_poll.c | 8 +
drivers/net/sxe2/sxe2_vsi.c | 146 ++
drivers/net/sxe2/sxe2_vsi.h | 12 +-
30 files changed, 6571 insertions(+), 22 deletions(-)
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.c
create mode 100644 drivers/net/sxe2/sxe2_ethdev_repr.h
create mode 100644 drivers/net/sxe2/sxe2_flow.c
create mode 100644 drivers/net/sxe2/sxe2_flow.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_action.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_engine.h
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.c
create mode 100644 drivers/net/sxe2/sxe2_flow_parse_pattern.h
create mode 100644 drivers/net/sxe2/sxe2_switchdev.c
create mode 100644 drivers/net/sxe2/sxe2_switchdev.h
diff --git a/drivers/common/sxe2/sxe2_common.c b/drivers/common/sxe2/sxe2_common.c
index f5ab8e9fa2..c000a55cd0 100644
--- a/drivers/common/sxe2/sxe2_common.c
+++ b/drivers/common/sxe2/sxe2_common.c
@@ -169,6 +169,37 @@ static int32_t sxe2_parse_class_type(const char *key, const char *value, void *a
return ret;
}
+static int32_t sxe2_parse_driver(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+
+ if (strcmp(value, "sxe2") != 0) {
+ PMD_LOG_ERR(COM, "%s: \"%s\" is not a valid driver.",
+ key, value);
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_parse_representor(const char *key, const char *value, void *args)
+{
+ int32_t ret = 0;
+
+ if (value == NULL || args == NULL)
+ goto l_end;
+
+ PMD_LOG_INFO(COM, "representor arg %s: \"%s\".", key, value);
+
+l_end:
+ return ret;
+}
+
static int32_t sxe2_common_device_setup(struct sxe2_common_device *cdev)
{
struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev);
@@ -394,6 +425,21 @@ static int32_t sxe2_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused
goto l_free_args;
}
+ ret = sxe2_kvargs_process(kv_info_p, SXE2_DEVARGS_KEY_DRIVER,
+ sxe2_parse_driver, NULL);
+ if (ret < 0) {
+ PMD_LOG_ERR(COM, "Unsupported sxe2 driver name: %s",
+ rte_dev->devargs->args);
+ goto l_free_args;
+ }
+
+ ret = sxe2_kvargs_process(kv_info_p, SXE2_DEVARGS_KEY_REPR,
+ sxe2_parse_representor, NULL);
+ if (ret < 0) {
+ PMD_LOG_ERR(COM, "Unsupported sxe2 driver representor: %s",
+ rte_dev->devargs->args);
+ goto l_free_args;
+ }
}
cdev = sxe2_common_device_alloc(rte_dev, class_type);
diff --git a/drivers/common/sxe2/sxe2_common.h b/drivers/common/sxe2/sxe2_common.h
index 482d29a7bb..b02b6317da 100644
--- a/drivers/common/sxe2/sxe2_common.h
+++ b/drivers/common/sxe2/sxe2_common.h
@@ -18,6 +18,8 @@
((cdev)->config.cmd_fd)
#define SXE2_DEVARGS_KEY_CLASS "class"
+#define SXE2_DEVARGS_KEY_DRIVER "driver"
+#define SXE2_DEVARGS_KEY_REPR "representor"
struct sxe2_class_driver;
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 4565046eae..65286299aa 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -71,4 +71,10 @@ sources += files(
'sxe2_mp.c',
'sxe2_stats.c',
'sxe2_irq.c',
+ 'sxe2_switchdev.c',
+ 'sxe2_ethdev_repr.c',
+ 'sxe2_flow.c',
+ 'sxe2_flow_parse_action.c',
+ 'sxe2_flow_parse_pattern.c',
+ 'sxe2_flow_parse_engine.c',
)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index d1f15084ed..6e2dd139a5 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -64,6 +64,23 @@ int32_t sxe2_drv_dev_caps_get(struct sxe2_adapter *adapter, struct sxe2_drv_dev_
return ret;
}
+int32_t sxe2_drv_switchdev_info_get(struct sxe2_adapter *adapter,
+ struct sxe2_switchdev_info *switchdev_info)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_DEV_GET_SWITCHDEV_INFO,
+ NULL, 0, switchdev_info,
+ sizeof(struct sxe2_switchdev_info));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "get switchdev info failed, ret=%d", ret);
+
+ return ret;
+}
+
int32_t sxe2_drv_dev_info_get(struct sxe2_adapter *adapter,
struct sxe2_drv_dev_info_resp *dev_info_resp)
{
@@ -167,7 +184,11 @@ static int32_t sxe2_rxq_ctxt_cfg_fill(struct sxe2_rx_queue *rxq,
req->q_cnt = rxq_cnt;
req->max_frame_size = dev_data->mtu + SXE2_ETH_OVERHEAD;
- ctxt->queue_id = rxq->queue_id;
+ if (adapter->is_dev_repr)
+ ctxt->queue_id = adapter->repr_priv_data->repr_q_id;
+ else
+ ctxt->queue_id = rxq->queue_id;
+
ctxt->depth = rxq->ring_depth;
ctxt->buf_len = RTE_ALIGN(rxq->rx_buf_len, SXE2_RXQ_CTXT_CFG_BUF_LEN_ALIGN);
ctxt->dma_addr = rxq->base_addr;
@@ -241,7 +262,10 @@ static void sxe2_txq_ctxt_cfg_fill(struct sxe2_tx_queue *txq,
ctxt = &req->cfg[q_idx];
ctxt->depth = txq[q_idx].ring_depth;
ctxt->dma_addr = txq[q_idx].base_addr;
- ctxt->queue_id = txq[q_idx].queue_id;
+ if (adapter->is_dev_repr)
+ ctxt->queue_id = adapter->repr_priv_data->repr_q_id;
+ else
+ ctxt->queue_id = txq[q_idx].queue_id;
ctxt->sched_mode = sxe2_sched_mode_get(adapter);
}
@@ -288,7 +312,10 @@ int32_t sxe2_drv_rxq_switch(struct sxe2_adapter *adapter, struct sxe2_rx_queue *
struct sxe2_drv_q_switch_req req;
req.vsi_id = rte_cpu_to_le_16(rxq->vsi->vsi_id);
- req.q_idx = rxq->queue_id;
+ if (adapter->is_dev_repr)
+ req.q_idx = adapter->repr_priv_data->repr_q_id;
+ else
+ req.q_idx = rxq->queue_id;
req.is_enable = (uint8_t)enable;
sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_RXQ_DISABLE,
@@ -310,7 +337,10 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
struct sxe2_drv_q_switch_req req;
req.vsi_id = rte_cpu_to_le_16(txq->vsi->vsi_id);
- req.q_idx = txq->queue_id;
+ if (adapter->is_dev_repr)
+ req.q_idx = adapter->repr_priv_data->repr_q_id;
+ else
+ req.q_idx = txq->queue_id;
req.is_enable = (uint8_t)enable;
req.sched_mode = sxe2_sched_mode_get(adapter);
@@ -326,6 +356,37 @@ int32_t sxe2_drv_txq_switch(struct sxe2_adapter *adapter, struct sxe2_tx_queue *
return ret;
}
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_drv_vsi_info_get_req vsi_info_get_req = {0};
+ struct sxe2_drv_vsi_info_get_resp vsi_info_get_resp = {0};
+
+ vsi_info_get_req.vsi_id = vsi->vsi_id;
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VSI_INFO_GET,
+ &vsi_info_get_req, sizeof(vsi_info_get_req),
+ &vsi_info_get_resp, sizeof(vsi_info_get_resp));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "switchdev cpvsi info get failed, ret=%d", ret);
+ goto l_end;
+ }
+
+ vsi->txqs.q_cnt = vsi_info_get_resp.used_queues.queues_cnt;
+ vsi->txqs.base_idx_in_func = vsi_info_get_resp.used_queues.base_idx_in_pf;
+
+ vsi->rxqs.q_cnt = vsi_info_get_resp.used_queues.queues_cnt;
+ vsi->rxqs.base_idx_in_func = vsi_info_get_resp.used_queues.base_idx_in_pf;
+
+ vsi->irqs.avail_cnt = vsi_info_get_resp.used_msix.msix_vectors_cnt;
+ vsi->irqs.base_idx_in_pf = vsi_info_get_resp.used_msix.base_idx_in_func;
+
+l_end:
+ return ret;
+}
+
int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
{
int32_t ret = 0;
@@ -614,6 +675,101 @@ int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set)
return ret;
}
+int32_t sxe2_drv_switchdev_uplink_config(struct sxe2_adapter *adapter, bool set)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_switchdev_uplink_info switchdev_uplink_info_req = {0};
+
+ switchdev_uplink_info_req.pf_id = adapter->pf_idx;
+ switchdev_uplink_info_req.is_set = set;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SWITCH_UPLINK,
+ &switchdev_uplink_info_req,
+ sizeof(switchdev_uplink_info_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "switchdev uplink info config failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_switchdev_repr_vf_config(struct sxe2_adapter *adapter,
+ struct sxe2_switchdev_repr_info *repr_vf,
+ bool set)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_switchdev_repr_info switchdev_repr_info_req = {0};
+
+ switchdev_repr_info_req.pf_id = adapter->pf_idx;
+ switchdev_repr_info_req.is_set = set;
+ switchdev_repr_info_req.cp_vsi_id = repr_vf->cp_vsi_id;
+ switchdev_repr_info_req.repr_pf_id = repr_vf->repr_pf_id;
+ switchdev_repr_info_req.repr_vf_id = repr_vf->repr_vf_id;
+ switchdev_repr_info_req.repr_q_id = repr_vf->repr_q_id;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SWITCH_REPR,
+ &switchdev_repr_info_req,
+ sizeof(switchdev_repr_info_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "switchdev repr info config failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_switchdev_mode_get(struct sxe2_adapter *adapter, bool *is_switchdev)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_switchdev_mode_info switchdev_mode_info_req = {0};
+ struct sxe2_switchdev_mode_info switchdev_mode_info_resp = {0};
+
+ switchdev_mode_info_req.pf_id = adapter->pf_idx;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SWITCH_MODE,
+ &switchdev_mode_info_req,
+ sizeof(switchdev_mode_info_req),
+ &switchdev_mode_info_resp,
+ sizeof(switchdev_mode_info_resp));
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "switchdev mode info get failed, ret=%d", ret);
+ else
+ *is_switchdev = (bool)switchdev_mode_info_resp.is_switchdev;
+
+ return ret;
+}
+
+int32_t sxe2_drv_switchdev_cpvsi_get(struct sxe2_adapter *adapter, uint16_t *cp_vsi_id)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_switchdev_cpvsi_info switchdev_cpvsi_resp = {0};
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_SWITCH_CPVSI,
+ NULL, 0,
+ &switchdev_cpvsi_resp,
+ sizeof(switchdev_cpvsi_resp));
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "switchdev cpvsi info get failed, ret=%d", ret);
+ else
+ *cp_vsi_id = switchdev_cpvsi_resp.cp_vsi_id;
+
+ return ret;
+}
+
int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add)
{
int32_t ret = 0;
@@ -1434,3 +1590,150 @@ int32_t sxe2_drv_mapping_stats_info_clear(struct rte_eth_dev *eth_dev)
return ret;
}
+
+int32_t sxe2_drv_flow_filter_add(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+ struct sxe2_drv_flow_filter_req req = { 0 };
+ struct sxe2_drv_flow_filter_resp resp = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ memcpy(&req.pattern_inner, &flow->pattern_inner, sizeof(req.pattern_inner));
+ memcpy(&req.pattern_outer, &flow->pattern_outer, sizeof(req.pattern_outer));
+ memcpy(&req.action, &flow->action, sizeof(req.action));
+ memcpy(&req.meta, &flow->meta, sizeof(req.meta));
+ req.engine_type = flow->engine_type;
+ req.flow_id = 0;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FILTER_ADD, &req,
+ sizeof(req), &resp, sizeof(resp));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add flow filter, ret: %d.", ret);
+ flow->flow_id = resp.flow_id;
+ flow->create_err = ret;
+ return ret;
+}
+
+int32_t sxe2_drv_flow_filter_del(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_drv_flow_filter_req req = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+ memcpy(&req.pattern_inner, &flow->pattern_inner, sizeof(req.pattern_inner));
+ memcpy(&req.pattern_outer, &flow->pattern_outer, sizeof(req.pattern_outer));
+ memcpy(&req.action, &flow->action, sizeof(req.action));
+ memcpy(&req.meta, &flow->meta, sizeof(req.meta));
+ req.engine_type = flow->engine_type;
+ req.flow_id = flow->flow_id;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FILTER_DEL, &req,
+ sizeof(req), NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to delete flow filter, flow id: %u, ret: %d.",
+ flow->flow_id, ret);
+ return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_get_stat_id(struct sxe2_adapter *adapter, uint32_t *stat_id)
+{
+ struct sxe2_drv_flow_fnav_get_stat_id_req req = { 0 };
+ struct sxe2_drv_flow_fnav_get_stat_id_resp resp = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_ALLOC,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get fnav stat id, ret: %d.", ret);
+ goto l_end;
+ }
+ *stat_id = resp.stat_id;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_free_stat(struct sxe2_adapter *adapter, uint32_t stat_id)
+{
+ struct sxe2_drv_flow_fnav_free_stat_id_req req = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ req.stat_id = stat_id;
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_FREE,
+ &req, sizeof(req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to free fnav stat id, ret: %d.", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_flow_fnav_query_stat(struct sxe2_adapter *adapter,
+ struct sxe2_fnav_cid_mgr *mgr)
+{
+ struct sxe2_drv_flow_fnav_query_stat_req req = { 0 };
+ struct sxe2_drv_flow_fnav_query_stat_resp resp = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ req.stat_id = mgr->stat_index;
+ req.stat_ctrl = mgr->count_type;
+ req.is_clear = 1;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_FLOW_FNAV_STAT_QUERY,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to query fnav stat, stat id: %u, ret: %d.",
+ req.stat_id, ret);
+ goto l_end;
+ }
+ mgr->hits += resp.stat_hits;
+ mgr->bytes += resp.stat_bytes;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
+ uint16_t *vsi_list, uint16_t vsi_cnt, bool set)
+{
+ int32_t ret = 0;
+ uint16_t idx;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_srcvsi_ext_cfg_req srcvsi_list_prune_cfg_req = {0};
+
+ srcvsi_list_prune_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ srcvsi_list_prune_cfg_req.is_add = set;
+ srcvsi_list_prune_cfg_req.srcvsi_cnt = vsi_cnt;
+ for (idx = 0; idx < vsi_cnt; idx++)
+ srcvsi_list_prune_cfg_req.srcvsi_list[idx] = vsi_list[idx];
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VSI_SRCVSI_PRUNE,
+ &srcvsi_list_prune_cfg_req,
+ sizeof(srcvsi_list_prune_cfg_req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "srcvsi prune config failed, ret=%d", ret);
+
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 3eb30078e1..52cd9922ad 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -12,6 +12,9 @@
int32_t sxe2_drv_dev_caps_get(struct sxe2_adapter *adapter,
struct sxe2_drv_dev_caps_resp *dev_caps);
+int32_t sxe2_drv_switchdev_info_get(struct sxe2_adapter *adapter,
+ struct sxe2_switchdev_info *switchdev_info);
+
int32_t sxe2_drv_dev_info_get(struct sxe2_adapter *adapter,
struct sxe2_drv_dev_info_resp *dev_info_resp);
@@ -64,6 +67,8 @@ int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+int32_t sxe2_drv_vsi_info_get(struct sxe2_adapter *adapter, struct sxe2_vsi *vsi);
+
int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
int32_t sxe2_drv_get_mac_stats(struct sxe2_adapter *adapter);
@@ -91,6 +96,15 @@ int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
+int32_t sxe2_drv_switchdev_uplink_config(struct sxe2_adapter *adapter, bool set);
+
+int32_t sxe2_drv_switchdev_repr_vf_config(struct sxe2_adapter *adapter,
+ struct sxe2_switchdev_repr_info *repr_vf, bool set);
+
+int32_t sxe2_drv_switchdev_cpvsi_get(struct sxe2_adapter *adapter, uint16_t *cp_vsi_id);
+
+int32_t sxe2_drv_switchdev_mode_get(struct sxe2_adapter *adapter, bool *is_switchdev);
+
int32_t sxe2_drv_mc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
int32_t sxe2_drv_vlan_config_query(struct sxe2_adapter *adapter);
@@ -122,4 +136,18 @@ int32_t sxe2_drv_rxq_bind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx, ui
int32_t sxe2_drv_rxq_unbind_irq(struct sxe2_adapter *adapter, uint16_t rxq_idx);
+int32_t sxe2_drv_flow_filter_add(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_drv_flow_filter_del(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_drv_flow_fnav_get_stat_id(struct sxe2_adapter *adapter, uint32_t *stat_id);
+
+int32_t sxe2_drv_flow_fnav_free_stat(struct sxe2_adapter *adapter, uint32_t stat_id);
+
+int32_t sxe2_drv_flow_fnav_query_stat(struct sxe2_adapter *adapter,
+ struct sxe2_fnav_cid_mgr *mgr);
+
+int32_t sxe2_drv_srcvsi_prune_config(struct sxe2_adapter *adapter,
+ uint16_t *vsi_list, uint16_t vsi_cnt, bool set);
+
#endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 807edfc4d6..38eb2d5cac 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -108,7 +108,6 @@ enum sxe2_phys_port_name_type {
SXE2_PHYS_PORT_NAME_TYPE_LEGACY,
SXE2_PHYS_PORT_NAME_TYPE_UPLINK,
SXE2_PHYS_PORT_NAME_TYPE_PFVF,
-
SXE2_PHYS_PORT_NAME_TYPE_UNKNOWN,
};
@@ -564,6 +563,60 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_queue_irq_bind_req {
uint8_t rsv[2];
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_uplink_info {
+ uint8_t pf_id;
+ uint8_t is_set;
+ uint8_t rsv[2];
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_repr_info {
+ uint8_t pf_id;
+ uint8_t is_set;
+ uint8_t rsv[2];
+ uint16_t cp_vsi_id;
+ uint16_t repr_pf_id;
+ uint16_t repr_vf_id;
+ uint16_t repr_q_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_filter_req {
+ uint32_t flow_id;
+ struct sxe2_flow_meta meta;
+ enum sxe2_flow_engine_type engine_type;
+ struct sxe2_flow_pattern pattern_outer;
+ struct sxe2_flow_pattern pattern_inner;
+ struct sxe2_flow_action action;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_filter_resp {
+ enum sxe2_flow_engine_type engine_type;
+ uint32_t flow_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_get_stat_id_req {
+ uint8_t need_update;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_get_stat_id_resp {
+ uint32_t stat_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_free_stat_id_req {
+ uint32_t stat_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_req {
+ uint32_t stat_id;
+ uint32_t stat_ctrl;
+ uint32_t is_clear;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_flow_fnav_query_stat_resp {
+ uint32_t stat_index;
+ uint64_t stat_hits;
+ uint64_t stat_bytes;
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 07d67321c9..24ac6b6038 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -33,9 +33,13 @@
#include "sxe2_ptype.h"
#include "sxe2_common_log.h"
#include "sxe2_mp.h"
+#include "sxe2_flow.h"
#include "sxe2_stats.h"
#include "sxe2_host_regs.h"
+#include "sxe2_switchdev.h"
#include "sxe2_ioctl_chnl_func.h"
+#include "sxe2_ethdev_repr.h"
+#include "sxe2vf_regs.h"
#define SXE2_PCI_VENDOR_ID_1 0x1ff2
#define SXE2_PCI_DEVICE_ID_PF_1 0x10b1
@@ -83,6 +87,27 @@ static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_
.reg_width = 10},
};
+static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_vf[SXE2_PCI_MAP_RES_MAX_COUNT] = {
+ [SXE2_PCI_MAP_RES_INVALID] = {.addr_base = 0,
+ .bar_idx = 0,
+ .reg_width = 0},
+ [SXE2_PCI_MAP_RES_DOORBELL_TX] = {.addr_base = SXE2VF_TXQ_TAIL(0),
+ .bar_idx = 0,
+ .reg_width = 4},
+ [SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL] = {.addr_base = SXE2VF_RXQ_TAIL(0),
+ .bar_idx = 0,
+ .reg_width = 4},
+ [SXE2_PCI_MAP_RES_IRQ_DYN] = {.addr_base = SXE2VF_VF_DYN_CTL(0),
+ .bar_idx = 0,
+ .reg_width = 4},
+ [SXE2_PCI_MAP_RES_IRQ_ITR] = {.addr_base = SXE2VF_VF_INT_ITR(0, 0),
+ .bar_idx = 0,
+ .reg_width = 4},
+ [SXE2_PCI_MAP_RES_IRQ_MSIX] = {.addr_base = SXE2VF_BAR4_MSIX_CTL(0),
+ .bar_idx = 4,
+ .reg_width = 0x10},
+};
+
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev);
static int32_t sxe2_dev_start(struct rte_eth_dev *dev);
static int32_t sxe2_dev_stop(struct rte_eth_dev *dev);
@@ -137,6 +162,7 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.rss_hash_update = sxe2_dev_rss_hash_update,
.rss_hash_conf_get = sxe2_dev_rss_hash_conf_get,
+ .flow_ops_get = sxe2_flow_ops_get,
.tm_ops_get = sxe2_tm_ops_get,
.stats_get = sxe2_stats_info_get,
@@ -566,7 +592,7 @@ static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
return ret;
}
-static void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
+void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
{
sxe2_mac_addr_uinit(dev);
(void)sxe2_filter_uinit(dev);
@@ -607,6 +633,16 @@ static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FC_STATE;
}
+static void sxe2_sw_representor_ctx_hw_cap_set(struct sxe2_adapter *adapter,
+ struct sxe2_drv_representor_caps *repr_caps)
+{
+ adapter->repr_ctxt.nb_vf = repr_caps->cnt_repr_vf;
+ if (adapter->repr_ctxt.nb_vf > 0) {
+ memcpy(adapter->repr_ctxt.repr_vf_id, repr_caps->repr_vf_id,
+ adapter->repr_ctxt.nb_vf * sizeof(struct sxe2_drv_vsi_caps));
+ }
+}
+
static void sxe2_sw_sched_hw_cap_set(struct sxe2_adapter *adapter,
struct sxe2_txsch_caps *txsch_caps)
{
@@ -636,20 +672,47 @@ static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter)
sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps);
+ sxe2_sw_representor_ctx_hw_cap_set(adapter, &dev_caps.repr_caps);
+
sxe2_sw_sched_hw_cap_set(adapter, &dev_caps.txsch_caps);
l_end:
return ret;
}
+static int32_t sxe2_switchdev_info_get(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ struct sxe2_switchdev_info switchdev_info = {0};
+
+ ret = sxe2_drv_switchdev_info_get(adapter, &switchdev_info);
+ if (ret)
+ goto l_end;
+ if (switchdev_info.primary && switchdev_info.representor) {
+ PMD_LOG_ERR(INIT, "device could not be both primary and representor");
+ ret = -ENODEV;
+ goto l_end;
+ }
+ adapter->switchdev_info = switchdev_info;
+l_end:
+ return ret;
+}
+
static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter)
{
int32_t ret = -1;
ret = sxe2_func_caps_get(adapter);
- if (ret)
+ if (ret) {
PMD_LOG_ERR(INIT, "get function caps failed, ret=%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_switchdev_info_get(adapter);
+ if (ret)
+ PMD_LOG_ERR(INIT, "get switchdev info failed, ret=%d", ret);
+l_end:
return ret;
}
@@ -935,7 +998,10 @@ int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev)
bar_info[1].seg_info = seg_info;
map_ctxt->bar_info = bar_info;
- map_ctxt->addr_info = sxe2_net_map_addr_info_pf;
+ if (adapter->dev_type == SXE2_DEV_T_VF)
+ map_ctxt->addr_info = sxe2_net_map_addr_info_vf;
+ else
+ map_ctxt->addr_info = sxe2_net_map_addr_info_pf;
ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
txq_cnt, txq_base);
@@ -1138,6 +1204,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto init_dev_info_err;
}
+ ret = sxe2_switchdev_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize switchdev mode, ret=[%d]", ret);
+ goto init_switchdev_err;
+ }
+
ret = sxe2_sw_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret);
@@ -1168,6 +1240,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto init_rss_err;
}
+ ret = sxe2_flow_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init flow, ret=%d", ret);
+ goto init_flow_err;
+ }
+
ret = sxe2_sched_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret);
@@ -1191,15 +1269,19 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
init_xstats_err:
(void)sxe2_sched_uinit(dev);
init_sched_err:
+ (void)sxe2_flow_uninit(dev);
+init_flow_err:
init_rss_err:
sxe2_security_uinit(dev);
init_security_err:
+ sxe2_eth_uinit(dev);
+init_eth_err:
sxe2_intr_uninit(dev);
init_irq_err:
sxe2_sw_uninit(dev);
init_sw_err:
- sxe2_eth_uinit(dev);
-init_eth_err:
+ (void)sxe2_switchdev_uninit(dev);
+init_switchdev_err:
init_dev_info_err:
sxe2_vsi_uninit(dev);
init_vsi_err:
@@ -1214,6 +1296,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
sxe2_mp_uninit(dev);
goto l_end;
}
+ sxe2_repr_all_close(dev);
(void)sxe2_dev_stop(dev);
(void)sxe2_queues_release(dev);
sxe2_mp_uninit(dev);
@@ -1222,6 +1305,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
sxe2_vsi_uninit(dev);
sxe2_security_uinit(dev);
sxe2_intr_uninit(dev);
+ (void)sxe2_switchdev_uninit(dev);
sxe2_sw_uninit(dev);
sxe2_eth_uinit(dev);
sxe2_dev_pci_map_uinit(dev);
@@ -1233,10 +1317,29 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
static int32_t sxe2_dev_uninit(struct rte_eth_dev *dev)
{
int32_t ret = 0;
+ int32_t i = 0;
+ struct sxe2_adapter *adapter = NULL;
+ struct rte_eth_dev *rep_dev = NULL;
if (rte_eal_process_type() != RTE_PROC_PRIMARY)
goto l_end;
+ adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ for (i = 0; i < adapter->repr_ctxt.nb_repr_vf; i++) {
+ rep_dev = adapter->repr_ctxt.vf_rep_eth_dev[i];
+ if (rep_dev) {
+ ret = rep_dev->dev_ops->dev_close(rep_dev);
+ if (ret)
+ goto l_end;
+ if (rep_dev->intr_handle)
+ rte_intr_instance_free(rep_dev->intr_handle);
+ ret = rte_eth_dev_release_port(rep_dev);
+ if (ret)
+ goto l_end;
+ adapter->repr_ctxt.vf_rep_eth_dev[i] = NULL;
+ }
+ }
+
ret = sxe2_dev_close(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Sxe2 dev close failed, ret=%d", ret);
@@ -1270,6 +1373,65 @@ static int32_t sxe2_eth_pmd_remove(struct sxe2_common_device *cdev)
return ret;
}
+static uint16_t sxe2_switchdev_repr_id_encode_get(struct sxe2_switchdev_info *switchdev_info)
+{
+ enum rte_eth_representor_type type;
+ uint16_t repr = switchdev_info->vf_num;
+ uint32_t pf = switchdev_info->pf_num;
+
+ switch (switchdev_info->port_name_type) {
+ case SXE2_PHYS_PORT_NAME_TYPE_UPLINK:
+ if (!switchdev_info->representor)
+ return UINT16_MAX;
+ type = RTE_ETH_REPRESENTOR_PF;
+ pf = switchdev_info->mpesw_owner;
+ break;
+ case SXE2_PHYS_PORT_NAME_TYPE_PFVF:
+ default:
+ type = RTE_ETH_REPRESENTOR_VF;
+ break;
+ }
+
+ return SXE2_REPRESENTOR_ID(pf, type, repr);
+}
+
+static bool sxe2_switchdev_repr_match(struct sxe2_adapter *adapter,
+ struct rte_eth_devargs *req_eth_da)
+{
+ uint32_t port_idx = 0;
+ uint32_t repr_idx;
+ uint16_t kernel_repr_id = sxe2_switchdev_repr_id_encode_get(&adapter->switchdev_info);
+ uint16_t repr_id;
+
+ switch (req_eth_da->type) {
+ case RTE_ETH_REPRESENTOR_PF:
+ break;
+ case RTE_ETH_REPRESENTOR_VF:
+ if (adapter->switchdev_info.port_name_type !=
+ SXE2_PHYS_PORT_NAME_TYPE_PFVF) {
+ rte_errno = EBUSY;
+ return false;
+ }
+ break;
+ case RTE_ETH_REPRESENTOR_NONE:
+ rte_errno = EBUSY;
+ return false;
+ default:
+ rte_errno = ENOTSUP;
+ return false;
+ }
+
+ for (repr_idx = 0; repr_idx < req_eth_da->nb_representor_ports; ++repr_idx) {
+ repr_id = SXE2_REPRESENTOR_ID(req_eth_da->ports[port_idx],
+ req_eth_da->type,
+ req_eth_da->representor_ports[repr_idx]);
+ if (repr_id == kernel_repr_id)
+ return true;
+ }
+ rte_errno = EBUSY;
+ return false;
+}
+
static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
struct rte_eth_devargs *req_eth_da __rte_unused,
uint16_t owner_id __rte_unused,
@@ -1311,10 +1473,34 @@ static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev,
goto l_release_port;
}
+ if (req_eth_da->nb_representor_ports > 0) {
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Representor requested but Switchdev not enabled");
+ ret = -ENOTSUP;
+ goto l_dev_uinit;
+ }
+
+ if (!sxe2_switchdev_repr_match(adapter, req_eth_da)) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Representor parameters mismatch");
+ ret = -ENOTSUP;
+ goto l_dev_uinit;
+ }
+
+ ret = sxe2_switchdev_repr_devs_init(adapter, req_eth_da);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init representor, ret=%d", ret);
+ goto l_dev_uinit;
+ }
+ } else {
+ PMD_DEV_LOG_DEBUG(adapter, INIT, "No representors requested, skipping.");
+ }
+
rte_eth_dev_probing_finish(eth_dev);
PMD_DEV_LOG_DEBUG(adapter, INIT, "Sxe2 eth pmd probe successful!");
goto l_end;
+l_dev_uinit:
+ (void)sxe2_dev_uninit(eth_dev);
l_release_port:
(void)rte_eth_dev_release_port(eth_dev);
l_end:
@@ -1384,6 +1570,11 @@ static struct sxe2_class_driver sxe2_eth_pmd = {
.intr_rmv = 1,
};
+bool sxe2_ethdev_check(struct rte_eth_dev *dev)
+{
+ return !strcmp(dev->device->driver->name, "sxe2_pci");
+}
+
RTE_INIT(rte_sxe2_pmd_init)
{
sxe2_common_init();
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 263d407587..756924ca0a 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -65,6 +65,9 @@ enum sxe2_fnav_tunnel_flag_type {
#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16))
#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
+#define SXE2_REPRESENTOR_ID(pf, type, repr) \
+ (((pf) << 14) + ((type) << 12) + ((repr) & 0xfff))
+
#define SXE2_I2C_EEPROM_DEV_ADDR 0xA0
#define SXE2_I2C_EEPROM_DEV_ADDR2 0xA2
#define SXE2_MODULE_TYPE_SFP 0x03
@@ -310,16 +313,20 @@ struct sxe2_adapter {
struct sxe2_vsi_context vsi_ctxt;
struct sxe2_filter_context filter_ctxt;
struct sxe2_rss_context rss_ctxt;
+ struct sxe2_flow_context flow_ctxt;
struct sxe2_link_context link_ctxt;
struct sxe2_ptp_context ptp_ctxt;
struct sxe2_sched_hw_cap sched_ctxt;
struct sxe2_tm_context tm_ctxt;
struct sxe2_devargs devargs;
struct sxe2_security_ctx security_ctx;
+ struct sxe2_repr_context repr_ctxt;
struct sxe2_switchdev_info switchdev_info;
bool rule_started;
bool flow_isolated;
+ bool flow_isolate_cfg;
uint16_t dev_port_id;
+ bool is_dev_repr;
uint64_t cap_flags;
enum sxe2_dev_type dev_type;
uint32_t ptype_tbl[SXE2_MAX_PTYPE_NUM];
@@ -338,6 +345,8 @@ void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter,
enum sxe2_pci_map_resource res_type,
uint16_t idx_in_func);
+bool sxe2_ethdev_check(struct rte_eth_dev *dev);
+
uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter);
struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter,
@@ -364,6 +373,8 @@ int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
+void sxe2_eth_uinit(struct rte_eth_dev *dev);
+
static inline bool
sxe2_dev_port_vlan_check(struct rte_eth_dev *dev)
{
diff --git a/drivers/net/sxe2/sxe2_ethdev_repr.c b/drivers/net/sxe2/sxe2_ethdev_repr.c
new file mode 100644
index 0000000000..a43991c379
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.c
@@ -0,0 +1,607 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_ethdev_repr.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_common.h"
+#include "sxe2_common_log.h"
+#include "sxe2_tx.h"
+#include "sxe2_rx.h"
+#include "sxe2_txrx.h"
+#include "sxe2_switchdev.h"
+#include "sxe2_ptype.h"
+#include "sxe2_mp.h"
+#include "sxe2_stats.h"
+#include "sxe2_flow.h"
+
+static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_repr[SXE2_PCI_MAP_RES_MAX_COUNT] = {
+ {0, 0, 0},
+ { SXE2_TXQ_LEGACY_DBLL(0), 0, 4},
+ { SXE2_RXQ_TAIL(0), 0, 4},
+ { SXE2_VF_DYN_CTL(0), 0, 4},
+ { SXE2_VF_INT_ITR(0, 0), 0, 4},
+ { SXE2_BAR4_MSIX_CTL(0), 4, 0x10},
+};
+
+static void sxe2_repr_dev_uinit(struct rte_eth_dev *dev);
+
+static int32_t sxe2_repr_promisc_enable(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+static int32_t sxe2_repr_promisc_disable(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+static int32_t sxe2_repr_allmulti_enable(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+static int32_t sxe2_repr_allmulti_disable(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+
+static int32_t sxe2_repr_dev_configure(struct rte_eth_dev *dev)
+{
+ dev->data->mtu = SXE2_FRAME_SIZE_MAX - SXE2_ETH_OVERHEAD;
+ return 0;
+}
+
+static int32_t sxe2_repr_dev_start(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ PMD_INIT_FUNC_TRACE();
+
+ ret = sxe2_queues_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init queues.");
+ goto l_end;
+ }
+
+ sxe2_rx_mode_func_set(dev);
+ sxe2_tx_mode_func_set(dev);
+
+ ret = sxe2_link_update_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_repr_rxq_intr_enable(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to enable rx queue intr");
+ goto l_end;
+ }
+
+ ret = sxe2_queues_start(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "enable queues failed");
+ goto l_start_queues_err;
+ }
+
+ dev->data->dev_started = 1;
+ adapter->started = 1;
+ goto l_end;
+l_start_queues_err:
+ (void)sxe2_rxq_intr_disable(dev);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_repr_dev_stop(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ PMD_INIT_FUNC_TRACE();
+
+ if (adapter->started == 0)
+ goto l_end;
+
+ sxe2_repr_rxq_intr_disable(dev);
+
+ sxe2_txqs_all_stop(dev);
+ sxe2_rxqs_all_stop(dev);
+
+ dev->data->dev_started = 0;
+ adapter->started = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_repr_dev_close(struct rte_eth_dev *dev)
+{
+ PMD_DEV_LOG_INFO(SXE2_DEV_PRIVATE_TO_ADAPTER(dev),
+ INIT, "repr close");
+ if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
+ sxe2_mp_uninit(dev);
+ goto l_end;
+ }
+ (void)sxe2_repr_dev_stop(dev);
+ (void)sxe2_queues_release(dev);
+ sxe2_mp_uninit(dev);
+ sxe2_repr_dev_uinit(dev);
+l_end:
+ return 0;
+}
+
+static int32_t sxe2_repr_dev_infos_get(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
+{
+ dev_info->max_rx_queues = 1;
+ dev_info->max_tx_queues = 1;
+ dev_info->min_rx_bufsize = SXE2_MIN_BUF_SIZE;
+ dev_info->max_rx_pktlen = SXE2_FRAME_SIZE_MAX;
+ dev_info->max_lro_pkt_size = SXE2_FRAME_SIZE_MAX * SXE2_RX_LRO_DESC_MAX_NUM;
+ dev_info->max_mtu = dev_info->max_rx_pktlen - SXE2_ETH_OVERHEAD;
+ dev_info->min_mtu = RTE_ETHER_MIN_MTU;
+ dev_info->max_mac_addrs = SXE2_NUM_MACADDR_MAX;
+
+ dev_info->rx_offload_capa =
+ RTE_ETH_RX_OFFLOAD_KEEP_CRC |
+ RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_RX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM;
+ dev_info->tx_offload_capa =
+ RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+
+ dev_info->tx_queue_offload_capa = RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
+
+ dev_info->default_rxconf = (struct rte_eth_rxconf) {
+ .rx_thresh = {
+ .pthresh = SXE2_DEFAULT_RX_PTHRESH,
+ .hthresh = SXE2_DEFAULT_RX_HTHRESH,
+ .wthresh = SXE2_DEFAULT_RX_WTHRESH,
+ },
+ .rx_free_thresh = SXE2_DEFAULT_RX_FREE_THRESH,
+ .rx_drop_en = 0,
+ .offloads = 0,
+ };
+
+ dev_info->default_txconf = (struct rte_eth_txconf) {
+ .tx_thresh = {
+ .pthresh = SXE2_DEFAULT_TX_PTHRESH,
+ .hthresh = SXE2_DEFAULT_TX_HTHRESH,
+ .wthresh = SXE2_DEFAULT_TX_WTHRESH,
+ },
+ .tx_free_thresh = SXE2_DEFAULT_TX_FREE_THRESH,
+ .tx_rs_thresh = SXE2_DEFAULT_TX_RSBIT_THRESH,
+ .offloads = 0,
+ };
+
+ dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = SXE2_MAX_RING_DESC,
+ .nb_min = SXE2_MIN_RING_DESC,
+ .nb_align = SXE2_ALIGN,
+ };
+
+ dev_info->tx_desc_lim = (struct rte_eth_desc_lim) {
+ .nb_max = SXE2_MAX_RING_DESC,
+ .nb_min = SXE2_MIN_RING_DESC,
+ .nb_align = SXE2_ALIGN,
+ .nb_mtu_seg_max = SXE2_TX_MTU_SEG_MAX,
+ .nb_seg_max = SXE2_MAX_RING_DESC,
+ };
+
+ dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_25G |
+ RTE_ETH_LINK_SPEED_50G | RTE_ETH_LINK_SPEED_100G;
+
+ dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+ dev_info->nb_tx_queues = dev->data->nb_tx_queues;
+
+ dev_info->default_rxportconf.burst_size = SXE2_RX_MAX_BURST;
+ dev_info->default_txportconf.burst_size = SXE2_TX_MAX_BURST;
+ dev_info->default_rxportconf.nb_queues = 1;
+ dev_info->default_txportconf.nb_queues = 1;
+ dev_info->default_rxportconf.ring_size = SXE2_RING_SIZE_MIN;
+ dev_info->default_txportconf.ring_size = SXE2_RING_SIZE_MIN;
+
+ dev_info->rx_seg_capa.offset_allowed = false;
+
+ dev_info->rx_seg_capa.offset_align_log2 = false;
+
+ return 0;
+}
+
+static const struct eth_dev_ops sxe2_switchdev_repr_dev_ops = {
+ .dev_configure = sxe2_repr_dev_configure,
+
+ .dev_start = sxe2_repr_dev_start,
+ .dev_stop = sxe2_repr_dev_stop,
+
+ .rx_queue_start = sxe2_rx_queue_start,
+ .rx_queue_stop = sxe2_rx_queue_stop,
+ .tx_queue_start = sxe2_tx_queue_start,
+ .tx_queue_stop = sxe2_tx_queue_stop,
+ .rx_queue_setup = sxe2_rx_queue_setup,
+ .rx_queue_release = sxe2_rx_queue_release,
+ .tx_queue_setup = sxe2_tx_queue_setup,
+ .tx_queue_release = sxe2_tx_queue_release,
+
+ .dev_close = sxe2_repr_dev_close,
+ .dev_infos_get = sxe2_repr_dev_infos_get,
+ .dev_supported_ptypes_get = sxe2_dev_supported_ptypes_get,
+ .link_update = sxe2_link_update,
+
+ .promiscuous_enable = sxe2_repr_promisc_enable,
+ .promiscuous_disable = sxe2_repr_promisc_disable,
+ .allmulticast_enable = sxe2_repr_allmulti_enable,
+ .allmulticast_disable = sxe2_repr_allmulti_disable,
+
+ .stats_get = sxe2_stats_info_get,
+ .stats_reset = sxe2_stats_info_reset,
+ .xstats_get = sxe2_xstats_info_get,
+ .xstats_get_names = sxe2_xstats_names_get,
+ .xstats_reset = sxe2_stats_info_reset,
+};
+
+void sxe2_repr_all_close(struct rte_eth_dev *dev)
+{
+ uint16_t vf_id;
+ struct rte_eth_dev *repr_eth_dev = NULL;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (adapter->repr_ctxt.nb_repr_vf) {
+ for (vf_id = 0; vf_id < adapter->repr_ctxt.nb_repr_vf; vf_id++) {
+ repr_eth_dev = adapter->repr_ctxt.vf_rep_eth_dev[vf_id];
+ if (!repr_eth_dev || repr_eth_dev->data->dev_started == 0)
+ continue;
+
+ (void)rte_eth_dev_stop(repr_eth_dev->data->port_id);
+ (void)rte_eth_dev_close(repr_eth_dev->data->port_id);
+ }
+ }
+}
+
+static void sxe2_repr_adapter_init(struct rte_eth_dev *dev_repr,
+ struct sxe2_adapter *parent_adapter,
+ uint16_t repr_id)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev_repr);
+
+ dev_repr->data->backer_port_id = parent_adapter->dev_port_id;
+ dev_repr->data->representor_id = repr_id;
+ dev_repr->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR;
+
+ adapter->is_dev_repr = true;
+ adapter->dev_port_id = dev_repr->data->port_id;
+ adapter->dev_type = parent_adapter->dev_type;
+ adapter->switchdev_info.is_switchdev = parent_adapter->switchdev_info.is_switchdev;
+ adapter->port_idx = parent_adapter->port_idx;
+ adapter->pf_idx = parent_adapter->pf_idx;
+ adapter->dev_info.pci = parent_adapter->dev_info.pci;
+ adapter->dev_info.fw = parent_adapter->dev_info.fw;
+}
+
+static int32_t sxe2_repr_eth_init(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+
+ ret = sxe2_filter_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize l2 filter, ret:%d", ret);
+ goto l_end;
+ }
+ ret = sxe2_link_update_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_mac_addr_init(dev);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to initialize mac address, ret:%d", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_repr_dev_pci_map_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *rep_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_pci_map_context *map_ctxt = &rep_adapter->map_ctxt;
+ struct sxe2_pci_map_bar_info *bar_info = NULL;
+ struct sxe2_pci_map_segment_info *seg_info = NULL;
+ uint16_t txq_cnt = rep_adapter->q_ctxt.qp_cnt_assign;
+ uint16_t txq_base = rep_adapter->q_ctxt.base_idx_in_pf;
+ uint16_t rxq_cnt = rep_adapter->q_ctxt.qp_cnt_assign;
+ uint16_t rxq_base = rep_adapter->q_ctxt.base_idx_in_pf;
+ uint16_t irq_cnt = rep_adapter->irq_ctxt.max_cnt_hw;
+ uint16_t irq_base = rep_adapter->irq_ctxt.base_idx_in_func;
+ int32_t ret = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ rep_adapter->dev_info.dev_data = dev->data;
+
+ map_ctxt->bar_cnt = 2;
+
+ bar_info = rte_zmalloc("repr_bar_info",
+ sizeof(struct sxe2_pci_map_bar_info) * map_ctxt->bar_cnt, 0);
+ if (bar_info == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to alloc bar_info");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ bar_info[0].bar_idx = 0;
+ bar_info[0].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+ seg_info = rte_zmalloc("repr_seg_info_bar0",
+ sizeof(struct sxe2_pci_map_segment_info) * bar_info[0].map_cnt, 0);
+ if (seg_info == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+ ret = -ENOMEM;
+ goto l_free_bar;
+ }
+
+ bar_info[0].seg_info = seg_info;
+
+ bar_info[1].bar_idx = 4;
+ bar_info[1].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT;
+ seg_info = rte_zmalloc("repr_seg_info_bar4",
+ sizeof(struct sxe2_pci_map_segment_info) * bar_info[1].map_cnt,
+ 0);
+ if (!seg_info) {
+ PMD_LOG_ERR(INIT, "Failed to alloc seg_info");
+ ret = -ENOMEM;
+ goto l_free_seg0;
+ }
+
+ bar_info[1].seg_info = seg_info;
+ map_ctxt->bar_info = bar_info;
+
+ map_ctxt->addr_info = sxe2_net_map_addr_info_repr;
+
+ ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_TX,
+ txq_cnt, txq_base);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to map txq doorbell addr, ret=%d", ret);
+ goto l_free_seg1;
+ }
+
+ ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL,
+ rxq_cnt, rxq_base);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to map rxq tail doorbell addr, ret=%d", ret);
+ goto l_free_txq;
+ }
+
+ ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_DYN,
+ irq_cnt, irq_base);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to map irq dyn addr, ret=%d", ret);
+ goto l_free_rxq_tail;
+ }
+
+ ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_ITR,
+ irq_cnt, irq_base);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to map irq itr addr, ret=%d", ret);
+ goto l_free_irq_dyn;
+ }
+
+ ret = sxe2_dev_pci_res_seg_map(rep_adapter, SXE2_PCI_MAP_RES_IRQ_MSIX,
+ irq_cnt, irq_base);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to map irq msix addr, ret=%d", ret);
+ goto l_free_irq_itr;
+ }
+ goto l_end;
+
+l_free_irq_itr:
+ (void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_IRQ_ITR);
+l_free_irq_dyn:
+ (void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_IRQ_DYN);
+l_free_rxq_tail:
+ (void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL);
+l_free_txq:
+ (void)sxe2_dev_pci_seg_unmap(rep_adapter, SXE2_PCI_MAP_RES_DOORBELL_TX);
+l_free_seg1:
+ if (bar_info[1].seg_info) {
+ rte_free(bar_info[1].seg_info);
+ bar_info[1].seg_info = NULL;
+ }
+l_free_seg0:
+ if (bar_info[0].seg_info) {
+ rte_free(bar_info[0].seg_info);
+ bar_info[0].seg_info = NULL;
+ }
+l_free_bar:
+ if (bar_info) {
+ rte_free(bar_info);
+ bar_info = NULL;
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_repr_dev_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter,
+ uint16_t repr_id)
+{
+ int32_t ret = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ sxe2_set_common_function(dev);
+
+ sxe2_repr_adapter_init(dev, parent_adapter, repr_id);
+
+ dev->dev_ops = &sxe2_switchdev_repr_dev_ops;
+
+ ret = sxe2_vsi_repr_main_vsi_create(dev, parent_adapter, repr_id);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to create representor main vsi, ret=[%d]", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_switchdev_repr_private_data_init(dev, parent_adapter, repr_id);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to fill representor private data, ret=[%d]", ret);
+ goto l_init_priv_data_err;
+ }
+
+ ret = sxe2_repr_dev_pci_map_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to pci addr map, ret=[%d]", ret);
+ goto l_init_pci_error;
+ }
+
+ ret = sxe2_switchdev_dev_info_init(dev, parent_adapter);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret);
+ goto l_init_dev_info_err;
+ }
+
+ ret = sxe2_flow_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init flow, ret=%d", ret);
+ goto l_init_flow_err;
+ }
+
+ ret = sxe2_repr_eth_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init device, status = %d", ret);
+ goto l_init_eth_err;
+ }
+
+ ret = sxe2_sw_irq_ctxt_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret);
+ goto l_init_sw_err;
+ }
+
+ goto l_end;
+
+l_init_sw_err:
+ sxe2_eth_uinit(dev);
+l_init_eth_err:
+ (void)sxe2_flow_uninit(dev);
+l_init_flow_err:
+l_init_dev_info_err:
+ sxe2_dev_pci_map_uinit(dev);
+l_init_pci_error:
+ (void)sxe2_switchdev_uninit(dev);
+l_init_priv_data_err:
+ sxe2_vsi_repr_main_vsi_destroy(dev);
+l_end:
+ return ret;
+}
+
+static void sxe2_repr_dev_uinit(struct rte_eth_dev *dev)
+{
+ sxe2_eth_uinit(dev);
+ (void)sxe2_flow_uninit(dev);
+ sxe2_dev_pci_map_uinit(dev);
+ (void)sxe2_switchdev_uninit(dev);
+ sxe2_vsi_repr_main_vsi_destroy(dev);
+}
+
+int32_t sxe2_switchdev_repr_devs_init(struct sxe2_adapter *adapter,
+ struct rte_eth_devargs *req_eth_da)
+{
+ struct rte_eth_dev *eth_dev = NULL;
+ int32_t ret;
+ uint16_t repr_idx = 0, tmp_repr_idx = 0;
+ char name[RTE_ETH_NAME_MAX_LEN];
+
+ if (req_eth_da->nb_representor_ports == 0) {
+ ret = 0;
+ goto l_end;
+ }
+
+ if (req_eth_da->nb_representor_ports > adapter->repr_ctxt.nb_vf) {
+ PMD_LOG_ERR(INIT, "Failed to create repr vsi, nb_representor_ports=%d, nb_vf=%d",
+ req_eth_da->nb_representor_ports, adapter->repr_ctxt.nb_vf);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_other_vsi_create(adapter, req_eth_da->nb_representor_ports);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to create representor vsi, ret=%d", ret);
+ goto l_release_port;
+ }
+
+ adapter->repr_ctxt.vf_rep_eth_dev = rte_zmalloc("sxe2_repr_ethdev",
+ req_eth_da->nb_representor_ports * sizeof(struct rte_eth_dev *), 0);
+ if (adapter->repr_ctxt.vf_rep_eth_dev == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to malloc representor eth dev.");
+ ret = -ENOMEM;
+ goto l_release_port;
+ }
+
+ for (repr_idx = 0; repr_idx < req_eth_da->nb_representor_ports; ++repr_idx) {
+ snprintf(name, sizeof(name), "sxe2_representor_c%dpf%d%s%u",
+ adapter->pf_idx, adapter->pf_idx,
+ "vf",
+ req_eth_da->representor_ports[repr_idx]);
+
+ eth_dev = rte_eth_dev_allocate(name);
+ if (!eth_dev) {
+ ret = -ENOMEM;
+ goto l_release_port;
+ }
+ eth_dev->data->dev_private = rte_zmalloc_socket(name,
+ sizeof(struct sxe2_adapter),
+ RTE_CACHE_LINE_SIZE,
+ rte_socket_id());
+
+ if (!eth_dev->data->dev_private) {
+ rte_eth_dev_release_port(eth_dev);
+ ret = -ENOMEM;
+ goto l_release_port;
+ }
+
+ eth_dev->device = rte_eth_devices[adapter->dev_info.dev_data->port_id].device;
+
+ ret = sxe2_repr_dev_init(eth_dev, adapter,
+ req_eth_da->representor_ports[repr_idx]);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Sxe2 dev init failed, ret=%d", ret);
+ rte_eth_dev_release_port(eth_dev);
+ goto l_release_port;
+ }
+
+ eth_dev->intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
+ if (eth_dev->intr_handle == NULL) {
+ PMD_LOG_ERR(INIT, "Sxe2 dev init representor intr_handle failed");
+ ret = -ENOMEM;
+ sxe2_repr_dev_uinit(eth_dev);
+ rte_eth_dev_release_port(eth_dev);
+ goto l_release_port;
+ }
+ adapter->repr_ctxt.vf_rep_eth_dev[repr_idx] = eth_dev;
+ rte_eth_dev_probing_finish(eth_dev);
+ }
+ adapter->repr_ctxt.nb_repr_vf = req_eth_da->nb_representor_ports;
+ goto l_end;
+
+l_release_port:
+ for (tmp_repr_idx = 0; tmp_repr_idx < repr_idx; ++tmp_repr_idx) {
+ struct rte_eth_dev *rep_dev = adapter->repr_ctxt.vf_rep_eth_dev[tmp_repr_idx];
+ if (rep_dev) {
+ sxe2_repr_dev_uinit(rep_dev);
+ if (rep_dev->intr_handle)
+ rte_intr_instance_free(rep_dev->intr_handle);
+ rte_eth_dev_release_port(rep_dev);
+ adapter->repr_ctxt.vf_rep_eth_dev[tmp_repr_idx] = NULL;
+ }
+ }
+
+ rte_free(adapter->repr_ctxt.vf_rep_eth_dev);
+ adapter->repr_ctxt.vf_rep_eth_dev = NULL;
+
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_ethdev_repr.h b/drivers/net/sxe2/sxe2_ethdev_repr.h
new file mode 100644
index 0000000000..71a666337f
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SX2_ETHDEV_REPR_H__
+#define __SX2_ETHDEV_REPR_H__
+#include <rte_compat.h>
+#include <rte_kvargs.h>
+#include <rte_time.h>
+#include <ethdev_driver.h>
+#include <ethdev_pci.h>
+#include <rte_tm_driver.h>
+#include <rte_io.h>
+#include <rte_ethdev.h>
+#include <rte_alarm.h>
+#include <rte_dev_info.h>
+
+#include "sxe2_vsi.h"
+#include "sxe2_irq.h"
+#include "sxe2_queue.h"
+struct sxe2_adapter;
+
+void sxe2_repr_all_close(struct rte_eth_dev *dev);
+
+int32_t sxe2_repr_dev_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter,
+ uint16_t repr_id);
+
+int32_t sxe2_switchdev_repr_devs_init(struct sxe2_adapter *adapter,
+ struct rte_eth_devargs *req_eth_da);
+
+#endif /* __SX2_ETHDEV_REPR_H__ */
diff --git a/drivers/net/sxe2/sxe2_filter.c b/drivers/net/sxe2/sxe2_filter.c
index b2a726f77e..175b886aa3 100644
--- a/drivers/net/sxe2/sxe2_filter.c
+++ b/drivers/net/sxe2/sxe2_filter.c
@@ -9,6 +9,7 @@
#include "sxe2_common_log.h"
#include "sxe2_ethdev.h"
#include "sxe2_cmd_chnl.h"
+#include "sxe2_switchdev.h"
static struct sxe2_mac_filter *sxe2_uc_filter_find(struct sxe2_adapter *adapter,
struct rte_ether_addr *macaddr)
@@ -698,16 +699,96 @@ static int32_t sxe2_all_filter_hw_set(struct sxe2_adapter *adapter)
return ret;
}
+static int32_t sxe2_uplink_hw_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (adapter->filter_ctxt.hw_uplink_config) {
+ if (adapter->dev_type == SXE2_DEV_T_PF) {
+ ret = sxe2_uplink_clear(adapter);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to clear uplink, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_uplink_config = false;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_uplink_hw_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->filter_ctxt.hw_uplink_config) {
+ if (adapter->dev_type == SXE2_DEV_T_PF) {
+ ret = sxe2_uplink_set(adapter);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set uplink, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_uplink_config = true;
+ ret = 0;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_repr_hw_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (adapter->filter_ctxt.hw_repr_config) {
+ if (adapter->dev_type == SXE2_DEV_T_PF ||
+ adapter->dev_type == SXE2_DEV_T_PF_BOND) {
+ ret = sxe2_repr_clear(adapter);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear repr, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_repr_config = false;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_repr_hw_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->filter_ctxt.hw_repr_config) {
+ if (adapter->dev_type == SXE2_DEV_T_PF ||
+ adapter->dev_type == SXE2_DEV_T_PF_BOND) {
+ ret = sxe2_repr_set(adapter);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set repr, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_repr_config = true;
+ ret = 0;
+ }
+ }
+l_end:
+ return ret;
+}
+
int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter)
{
int32_t ret = 0;
- if (!adapter->flow_isolated && !adapter->switchdev_info.is_switchdev &&
- adapter->rule_started) {
+ if (!adapter->flow_isolated &&
+ !adapter->switchdev_info.is_switchdev &&
+ adapter->rule_started)
adapter->filter_ctxt.cur_l2_config = true;
- } else {
+ else
adapter->filter_ctxt.cur_l2_config = false;
- }
if (adapter->filter_ctxt.cur_l2_config !=
adapter->filter_ctxt.hw_l2_config) {
@@ -724,6 +805,38 @@ int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter)
return ret;
}
+int32_t sxe2_switchdev_rule_update(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->flow_isolated &&
+ adapter->switchdev_info.is_switchdev) {
+ adapter->filter_ctxt.cur_uplink_config = true;
+ adapter->filter_ctxt.cur_repr_config = true;
+ } else {
+ adapter->filter_ctxt.cur_uplink_config = false;
+ adapter->filter_ctxt.cur_repr_config = false;
+ }
+
+ if (adapter->filter_ctxt.cur_uplink_config !=
+ adapter->filter_ctxt.hw_uplink_config) {
+ if (adapter->filter_ctxt.cur_uplink_config)
+ ret = sxe2_uplink_hw_set(adapter);
+ else
+ ret = sxe2_uplink_hw_clear(adapter);
+ }
+
+ if (adapter->filter_ctxt.cur_repr_config !=
+ adapter->filter_ctxt.hw_repr_config) {
+ if (adapter->filter_ctxt.cur_repr_config)
+ ret = sxe2_repr_hw_set(adapter);
+ else
+ ret = sxe2_repr_hw_clear(adapter);
+ }
+
+ return ret;
+}
+
int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
diff --git a/drivers/net/sxe2/sxe2_filter.h b/drivers/net/sxe2/sxe2_filter.h
index 6262e8c845..b2538ed22f 100644
--- a/drivers/net/sxe2/sxe2_filter.h
+++ b/drivers/net/sxe2/sxe2_filter.h
@@ -89,6 +89,8 @@ int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter);
int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev);
+int32_t sxe2_switchdev_rule_update(struct sxe2_adapter *adapter);
+
int32_t sxe2_filter_rule_start(struct rte_eth_dev *dev);
int32_t sxe2_filter_init(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
new file mode 100644
index 0000000000..6999cb0725
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -0,0 +1,1337 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <sys/queue.h>
+#include <unistd.h>
+#include "sxe2_ethdev.h"
+#include "sxe2_flow.h"
+#include "sxe2_flow_parse_pattern.h"
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_flow_parse_engine.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_common_log.h"
+
+static int32_t sxe2_check_para(const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ if (!pattern) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+ NULL, "NULL pattern.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+
+ if (!actions) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_NUM,
+ NULL, "NULL action.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+
+ if (!attr) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR,
+ NULL, "NULL attribute.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_valid_attr(const struct rte_flow_attr *attr, struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+
+ if (!attr->ingress) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
+ attr, "Only support ingress.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+
+ if (attr->egress) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
+ attr, "Not support egress.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+
+ if (attr->group >= 4) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
+ attr, "Not support group >= 4.");
+ ret = -rte_errno;
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_hdr_duplicate(struct sxe2_flow_item *item_new,
+ struct sxe2_flow_item *item_exist)
+{
+ int32_t ret = 0;
+ uint16_t i = 0;
+ uint16_t size = sizeof(struct sxe2_flow_item);
+ union sxe2_flow_item_raw item_raw_new;
+ union sxe2_flow_item_raw item_raw_exist;
+ rte_memcpy(&item_raw_new.item, item_new, size);
+ rte_memcpy(&item_raw_exist.item, item_exist, size);
+
+ for (i = 0; i < size; i++) {
+ if (item_raw_new.raw[i] != item_raw_exist.raw[i])
+ goto l_end;
+ }
+ ret = -EEXIST;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_flow_duplicate(struct sxe2_flow *flow_new,
+ struct sxe2_flow *flow_exist)
+{
+ int32_t ret = 0;
+ int32_t ret_mask1 = 0;
+ int32_t ret_mask2 = 0;
+ int32_t ret_spec1 = 0;
+ int32_t ret_spec2 = 0;
+
+ if (flow_new->engine_type != flow_exist->engine_type)
+ goto l_end;
+ if (flow_new->meta.flow_type != flow_exist->meta.flow_type)
+ goto l_end;
+ if (!sxe2_bitmap_equal(flow_new->flow_type, flow_exist->flow_type,
+ SXE2_EXPANSION_MAX))
+ goto l_end;
+ if (flow_new->meta.flow_prio != flow_exist->meta.flow_prio)
+ goto l_end;
+
+ ret_mask1 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_outer.item_mask,
+ &flow_exist->pattern_outer.item_mask);
+ ret_mask2 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_inner.item_mask,
+ &flow_exist->pattern_inner.item_mask);
+
+ ret_spec1 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_outer.item_spec,
+ &flow_exist->pattern_outer.item_spec);
+ ret_spec2 = sxe2_flow_check_hdr_duplicate(&flow_new->pattern_inner.item_spec,
+ &flow_exist->pattern_inner.item_spec);
+
+ if (flow_new->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ if (ret_mask1 == 0 || ret_mask2 == 0) {
+ ret = -EEXIST;
+ goto l_end;
+ }
+
+ if (ret_spec1 == -EEXIST && ret_spec2 == -EEXIST) {
+ ret = -EEXIST;
+ goto l_end;
+ }
+ } else {
+ if (ret_mask1 == -EEXIST && ret_mask2 == -EEXIST &&
+ ret_spec1 == -EEXIST && ret_spec2 == -EEXIST) {
+ ret = -EEXIST;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_flow_list_duplicate(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow *sxe2_flow_new = NULL;
+ struct rte_flow *rte_flow_exist = NULL;
+ struct sxe2_flow *sxe2_flow_exist = NULL;
+ TAILQ_FOREACH(sxe2_flow_new, &flow_list->sxe2_flow_list, next) {
+ TAILQ_FOREACH(rte_flow_exist, &adapter->flow_ctxt.rte_flow_list, next) {
+ TAILQ_FOREACH(sxe2_flow_exist, &rte_flow_exist->sxe2_flow_list, next) {
+ ret = sxe2_flow_check_flow_duplicate(sxe2_flow_new,
+ sxe2_flow_exist);
+ if (ret != 0)
+ goto l_end;
+ }
+ }
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_function(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+ int32_t ret = 0;
+
+ uint16_t flow_dst_vsi = UINT16_MAX;
+
+ if (adapter->dev_type == SXE2_DEV_T_VF) {
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types)) {
+ flow_dst_vsi = flow->action.vsi.vsi_index;
+
+ if (adapter->vsi_ctxt.dpdk_vsi_id != flow_dst_vsi &&
+ adapter->vsi_ctxt.kernel_vsi_id != flow_dst_vsi) {
+ PMD_LOG_ERR(DRV, "Failed to redirect other function");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to redirect other function");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types)) {
+ PMD_LOG_ERR(DRV,
+ "Failed to redirect multiple driver or function");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to redirect multiple driver or function");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+
+ if (!adapter->flow_isolated &&
+ flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ PMD_LOG_ERR(DRV,
+ "Failed to switch engine rules in a non-flow-isolated state");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to switch engine rules in a non-flow-isolated state");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+
+ if (adapter->switchdev_info.is_switchdev &&
+ flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ PMD_LOG_ERR(DRV,
+ "Failed to switch engine rules in a switchdev mode state");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to switch engine rules in a switchdev mode state");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+ }
+
+ if (adapter->is_dev_repr) {
+ if (flow->engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+ PMD_LOG_ERR(DRV,
+ "Failed to config non switch engine rules in representor dev");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to config non switch engine rules in representor dev");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_QUEUE, flow->action.act_types) ||
+ sxe2_test_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types)) {
+ PMD_LOG_ERR(DRV,
+ "Failed to config queue rules in representor dev");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to config queue rules in representor dev");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+ }
+
+ if (adapter->switchdev_info.is_switchdev &&
+ adapter->dev_type == SXE2_DEV_T_PF &&
+ !adapter->is_dev_repr &&
+ !adapter->flow_isolated) {
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types)) {
+ if (flow->action.vsi.vsi_index == adapter->vsi_ctxt.dpdk_vsi_id) {
+ PMD_LOG_ERR(DRV,
+ "Failed to config rx fwd rule to current uplink dev");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to config rx fwd rule to current uplink dev");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_meta_proc(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+ int32_t ret = 0;
+
+ if (attr->priority >= 1) {
+ if (flow->engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+ PMD_LOG_ERR(DRV, "Only support priority 0.");
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Only support priority 0.");
+ ret = -rte_errno;
+ goto l_end;
+ } else if (!adapter->switchdev_info.is_switchdev) {
+ PMD_LOG_ERR(DRV, "Legacy mode only support priority 0.");
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
+ attr, "Legacy mode only priority 0.");
+ ret = -rte_errno;
+ goto l_end;
+ } else {
+ flow->meta.flow_prio = attr->priority;
+ }
+ }
+
+ flow->meta.flow_src_vsi = adapter->vsi_ctxt.dpdk_vsi_id;
+
+ if (adapter->is_dev_repr && adapter->repr_priv_data &&
+ adapter->repr_priv_data->parent_adapter) {
+ flow->meta.flow_rule_vsi =
+ adapter->repr_priv_data->parent_adapter->vsi_ctxt.dpdk_vsi_id;
+ } else {
+ flow->meta.flow_rule_vsi = adapter->vsi_ctxt.dpdk_vsi_id;
+ }
+
+ if (flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ flow->meta.switch_pattern_dup_allow =
+ adapter->devargs.flow_dup_pattern_mode;
+
+ flow->meta.switch_src_direct = SXE2_FLOW_SW_DIRECT_RX;
+
+ if (adapter->switchdev_info.is_switchdev && adapter->is_dev_repr) {
+ flow->meta.switch_src_direct = SXE2_FLOW_SW_DIRECT_TX;
+ flow->meta.flow_src_vsi = adapter->repr_priv_data->repr_vf_vsi_id;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_src_split_proc(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+ int32_t ret = 0;
+
+ int32_t idx = 0;
+ uint8_t flow_cnt = 0;
+ uint8_t flow_create_cnt = 0;
+ uint8_t flow_bond_num = 1;
+ uint16_t flow_src_vsi[SXE2_MAX_DRV_TYPE_CNT][SXE2_MAX_BOND_MEMBER_CNT];
+ uint16_t flow_dst_vsi = UINT16_MAX;
+ struct sxe2_flow *flow_new = NULL;
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types))
+ flow_dst_vsi = flow->action.vsi.vsi_index;
+
+ for (idx = 0; idx < SXE2_MAX_BOND_MEMBER_CNT; idx++) {
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] = UINT16_MAX;
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+ }
+
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][0] = adapter->vsi_ctxt.dpdk_vsi_id;
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][0] = adapter->vsi_ctxt.kernel_vsi_id;
+ if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV ||
+ flow->engine_type == SXE2_FLOW_ENGINE_ACL) {
+ if (!adapter->devargs.func_flow_direct_en &&
+ adapter->dev_type != SXE2_DEV_T_PF_BOND) {
+ if (adapter->flow_isolated) {
+ for (idx = 0; idx < flow_bond_num; idx++) {
+ if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] !=
+ UINT16_MAX)
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] =
+ UINT16_MAX;
+ }
+ } else {
+ for (idx = 0; idx < flow_bond_num; idx++)
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+ }
+ }
+
+ for (idx = 0; idx < flow_bond_num; idx++) {
+ if (flow_dst_vsi == flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx])
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+ if (flow_dst_vsi == flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx])
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] = UINT16_MAX;
+ }
+ } else {
+ for (idx = 0; idx < flow_bond_num; idx++)
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] = UINT16_MAX;
+ }
+
+ if (adapter->switchdev_info.is_switchdev && adapter->is_dev_repr) {
+ flow_bond_num = 1;
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][0] =
+ adapter->repr_priv_data->repr_vf_u_vsi_id;
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][0] =
+ adapter->repr_priv_data->repr_vf_k_vsi_id;
+ }
+
+ for (idx = 0; idx < flow_bond_num; idx++) {
+ if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] != UINT16_MAX)
+ flow_cnt++;
+ if (flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] != UINT16_MAX)
+ flow_cnt++;
+ }
+
+ if (flow_cnt == 0) {
+ PMD_LOG_ERR(DRV, "Failed to redirect same device.");
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to redirect same device");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ for (idx = 0; idx < flow_bond_num; idx++) {
+ if (flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx] != UINT16_MAX) {
+ if (flow_create_cnt == 0) {
+ flow->meta.flow_src_vsi =
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx];
+ flow_create_cnt++;
+ } else {
+ flow_new = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+ if (!flow_new) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rte_memcpy(flow_new, flow, sizeof(struct sxe2_flow));
+ TAILQ_INSERT_TAIL(sxe2_flow_list, flow_new, next);
+ flow_new->meta.flow_src_vsi =
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_DPDK][idx];
+ flow_create_cnt++;
+ }
+ }
+ if (flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx] != UINT16_MAX) {
+ if (flow_create_cnt == 0) {
+ flow->meta.flow_src_vsi =
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx];
+ flow_create_cnt++;
+ } else {
+ flow_new = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+ if (!flow_new) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rte_memcpy(flow_new, flow, sizeof(struct sxe2_flow));
+ TAILQ_INSERT_TAIL(sxe2_flow_list, flow_new, next);
+ flow_new->meta.flow_src_vsi =
+ flow_src_vsi[SXE2_MAX_DRV_TYPE_KERNEL][idx];
+ flow_create_cnt++;
+ }
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_adjust_action(struct rte_eth_dev *dev __rte_unused,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error __rte_unused)
+{
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = NULL;
+ int32_t ret = 0;
+ int32_t dest_num = 0;
+ int32_t pass_num = 0;
+ int32_t mark_num = 0;
+ int32_t count_num = 0;
+ int32_t drop_num = 0;
+
+ TAILQ_FOREACH(flow, sxe2_flow_list, next) {
+ if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ dest_num = sxe2_test_bit(SXE2_FLOW_ACTION_Q_REGION,
+ flow->action.act_types) +
+ sxe2_test_bit(SXE2_FLOW_ACTION_QUEUE,
+ flow->action.act_types);
+ pass_num = sxe2_test_bit(SXE2_FLOW_ACTION_PASSTHRU,
+ flow->action.act_types);
+ mark_num = sxe2_test_bit(SXE2_FLOW_ACTION_MARK,
+ flow->action.act_types);
+ count_num = sxe2_test_bit(SXE2_FLOW_ACTION_COUNT,
+ flow->action.act_types);
+ drop_num = sxe2_test_bit(SXE2_FLOW_ACTION_DROP,
+ flow->action.act_types);
+
+ if (dest_num) {
+ sxe2_clear_bit(SXE2_FLOW_ACTION_PASSTHRU,
+ flow->action.act_types);
+ pass_num = 0;
+ sxe2_clear_bit(SXE2_FLOW_ACTION_TO_VSI,
+ flow->action.act_types);
+ }
+
+ if (pass_num)
+ flow->action.passthru.vsi_index = flow->meta.flow_src_vsi;
+
+ if (mark_num) {
+ if (dest_num == 0) {
+ flow->action.q_region.q_index = 0;
+ flow->action.q_region.region = 7;
+ flow->action.q_region.vsi_index = flow->meta.flow_src_vsi;
+ sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION,
+ flow->action.act_types);
+ dest_num++;
+ }
+ sxe2_clear_bit(SXE2_FLOW_ACTION_PASSTHRU,
+ flow->action.act_types);
+ pass_num = 0;
+ }
+ if (count_num) {
+ if (dest_num == 0 && drop_num == 0) {
+ if (pass_num == 0) {
+ sxe2_set_bit(SXE2_FLOW_ACTION_PASSTHRU,
+ flow->action.act_types);
+ flow->action.passthru.vsi_index =
+ flow->meta.flow_src_vsi;
+ pass_num++;
+ }
+ }
+ }
+ PMD_LOG_DEBUG(DRV, "dest_num: %d, pass_num: %d, mark_num: %d, count_num: "
+ "%d, drop_num: %d", dest_num, pass_num, mark_num, count_num,
+ drop_num);
+ PMD_LOG_DEBUG(DRV, "src_vsi: %d", flow->meta.flow_src_vsi);
+ }
+ }
+
+ return ret;
+}
+
+static int32_t sxe2_flow_check_item_empty(uint8_t *item, uint16_t size)
+{
+ uint16_t i = 0;
+
+ for (i = 0; i < size; i++) {
+ if (item[i] != 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int32_t sxe2_flowlist_add_proto_type(struct rte_eth_dev *dev __rte_unused,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow *flow = TAILQ_FIRST(sxe2_flow_list);
+ struct sxe2_flow_pattern *pattern = &flow->pattern_outer;
+ int32_t ret = 0;
+
+ if (flow->engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4, flow->flow_type) &&
+ sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.ipv4,
+ sizeof(pattern->item_mask.ipv4)) == 0) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+ pattern->item_spec.eth.ether_type =
+ rte_cpu_to_be_16(SXE2_FLOW_ETH_TYPE_IPV4);
+ pattern->item_mask.eth.ether_type = 0xffff;
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6, flow->flow_type) &&
+ sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.ipv6,
+ sizeof(pattern->item_mask.ipv6)) == 0) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+ pattern->item_spec.eth.ether_type =
+ rte_cpu_to_be_16(SXE2_FLOW_ETH_TYPE_IPV6);
+ pattern->item_mask.eth.ether_type = 0xffff;
+ }
+
+ if (flow->meta.tunnel_type == SXE2_FLOW_TUNNEL_TYPE_NONE) {
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_UDP, flow->flow_type) &&
+ sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.udp,
+ sizeof(pattern->item_mask.udp)) == 0) {
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4,
+ flow->flow_type)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+ pattern->item_spec.ipv4.protocol =
+ SXE2_FLOW_IP_PROTOCOL_UDP;
+ pattern->item_mask.ipv4.protocol = 0xff;
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6,
+ flow->flow_type)) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, ENOENT,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "UDP after IPv6 must has pattern item.");
+ PMD_LOG_ERR(DRV,
+ "UDP after IPv6 must has pattern item.");
+ goto l_end;
+ }
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_TCP, flow->flow_type) &&
+ sxe2_flow_check_item_empty((uint8_t *)&pattern->item_mask.tcp,
+ sizeof(pattern->item_mask.tcp)) == 0) {
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV4,
+ flow->flow_type)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT,
+ pattern->map_spec);
+ pattern->item_spec.ipv4.protocol =
+ SXE2_FLOW_IP_PROTOCOL_TCP;
+ pattern->item_mask.ipv4.protocol = 0xff;
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_IPV6,
+ flow->flow_type)) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, ENOENT,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "TCP after IPv6 must has pattern item.");
+ PMD_LOG_ERR(DRV,
+ "TCP after IPv6 must has pattern item.");
+ goto l_end;
+ }
+ }
+ if (sxe2_test_bit(SXE2_EXPANSION_OUTER_SCTP,
+ flow->flow_type)) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, ENOENT,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "SWITCH not support SCTP.");
+ PMD_LOG_ERR(DRV, "SWITCH not support SCTP.");
+ goto l_end;
+ }
+ }
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_tunnel_split_proc(struct rte_eth_dev *dev __rte_unused,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ struct sxe2_flow_list_t *sxe2_flow_list = &flow_list->sxe2_flow_list;
+ struct sxe2_flow_list_t tunnel_flow_list;
+ struct sxe2_flow *sxe2_flow_exist = NULL;
+ struct sxe2_flow *sxe2_flow_new = NULL;
+ struct sxe2_flow_pattern *pattern = NULL;
+ int32_t ret = 0;
+
+ TAILQ_INIT(&tunnel_flow_list);
+
+ TAILQ_FOREACH(sxe2_flow_exist, sxe2_flow_list, next) {
+ if (sxe2_flow_exist->engine_type != SXE2_FLOW_ENGINE_SWITCH)
+ continue;
+ if (sxe2_test_bit(SXE2_FLOW_FLD_ID_IPV4_PROT,
+ sxe2_flow_exist->pattern_outer.map_spec)) {
+ pattern = &sxe2_flow_exist->pattern_outer;
+ if ((pattern->item_spec.ipv4.protocol &
+ pattern->item_mask.ipv4.protocol) ==
+ (SXE2_FLOW_IP_PROTOCOL_GRE &
+ pattern->item_mask.ipv4.protocol)) {
+ sxe2_flow_new = rte_zmalloc("sxe2_flow",
+ sizeof(struct sxe2_flow), 0);
+ if (!sxe2_flow_new) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rte_memcpy(sxe2_flow_new, sxe2_flow_exist,
+ sizeof(struct sxe2_flow));
+ pattern = &sxe2_flow_new->pattern_outer;
+ sxe2_flow_new->meta.tunnel_type =
+ SXE2_FLOW_TUNNEL_TYPE_GRE;
+ sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+ pattern->item_spec.ipv4.protocol =
+ SXE2_FLOW_IP_PROTOCOL_GRE;
+ pattern->item_mask.ipv4.protocol = 0xff;
+ TAILQ_INSERT_TAIL(&tunnel_flow_list, sxe2_flow_new, next);
+ }
+ }
+ }
+ TAILQ_FOREACH(sxe2_flow_exist, &tunnel_flow_list, next)
+ TAILQ_INSERT_TAIL(sxe2_flow_list, sxe2_flow_exist, next);
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_post_proc(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ struct rte_flow *flow_list,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+
+ ret = sxe2_flowlist_add_proto_type(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_check_function(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_meta_proc(dev, attr, flow_list, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_src_split_proc(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_adjust_action(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_tunnel_split_proc(dev, flow_list, error);
+ if (ret)
+ goto l_end;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_validate_with_flow(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_flow *flow = NULL;
+
+ ret = sxe2_check_para(attr, pattern, actions, error);
+ if (ret != 0)
+ goto l_end;
+
+ ret = sxe2_flow_valid_attr(attr, error);
+ if (ret != 0)
+ goto l_end;
+
+ flow = rte_zmalloc("sxe2_flow", sizeof(*flow), 0);
+ if (!flow) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ TAILQ_INSERT_TAIL(&flow_list->sxe2_flow_list, flow, next);
+ flow->create_err = -1;
+
+ ret = sxe2_flow_parse_pattern(dev, pattern, error, flow);
+ if (ret != 0)
+ goto l_end;
+
+ ret = sxe2_flow_parse_engine(dev, attr, actions, error, flow);
+ if (ret != 0)
+ goto l_end;
+
+ ret = sxe2_flow_parse_action(dev, actions, error, flow);
+ if (ret != 0)
+ goto l_end;
+
+ ret = sxe2_flow_post_proc(dev, attr, flow_list, error);
+ if (ret != 0)
+ goto l_end;
+
+ ret = sxe2_flow_check_flow_list_duplicate(dev, flow_list);
+ if (ret != 0) {
+ rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_ITEM,
+ NULL, "Duplicate flow.");
+ PMD_LOG_ERR(DRV, "Duplicate flow.");
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+static const char *sxe2_flow_convert_ret_to_flow_msg(int32_t ret)
+{
+ const char *msg = NULL;
+ if (ret > 0)
+ ret = -ret;
+ switch (ret) {
+ case -ENOMEM:
+ msg = "no memory";
+ break;
+ case -ENOTSUP:
+ msg = "not support";
+ break;
+ case -EEXIST:
+ msg = "rule already exist";
+ break;
+ case -ETIMEDOUT:
+ msg = "timeout";
+ break;
+ case -EINVAL:
+ msg = "invalid parameter";
+ break;
+ case -ENOSPC:
+ msg = "no space";
+ break;
+ case -ENOENT:
+ msg = "no such rule";
+ break;
+ default:
+ msg = "unknown error";
+ break;
+ }
+ return msg;
+}
+
+static int32_t sxe2_flow_rte_list_free(struct sxe2_adapter *adapter,
+ struct rte_flow **flow_ptr,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ int32_t ret1 = 0;
+ struct rte_flow *flow = *flow_ptr;
+ struct rte_flow *flow_temp = NULL;
+ struct sxe2_flow *hw_flow = NULL;
+ struct sxe2_flow *hw_flow_temp = NULL;
+ struct sxe2_fnav_cid_mgr *mgr = NULL;
+ rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+ TAILQ_FOREACH(flow_temp, &adapter->flow_ctxt.rte_flow_list, next) {
+ if (flow_temp == flow)
+ TAILQ_REMOVE(&adapter->flow_ctxt.rte_flow_list, flow, next);
+ }
+
+ TAILQ_FOREACH_SAFE(hw_flow, &flow->sxe2_flow_list, next, hw_flow_temp) {
+ if (hw_flow->create_err == 0) {
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, hw_flow->action.act_types)) {
+ ret = sxe2_flow_query_mgr(adapter, hw_flow, &mgr, error);
+ if (ret) {
+ PMD_LOG_ERR(DRV,
+ "Failed to query flow count, flow id: %u, ret: %d.",
+ hw_flow->flow_id, ret);
+ rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to query flow count");
+ ret1 = ret;
+ }
+ }
+
+ ret = sxe2_drv_flow_filter_del(adapter, hw_flow);
+ if (ret) {
+ PMD_LOG_ERR(DRV,
+ "Failed to delete flow filter, ret: %d:%s",
+ ret, sxe2_flow_convert_ret_to_flow_msg(ret));
+ rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "Failed to delete flow filter");
+ ret1 = ret;
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, hw_flow->action.act_types)) {
+ ret = sxe2_flow_free_mgr(adapter, hw_flow,
+ &mgr, error);
+ if (ret)
+ ret1 = ret;
+ }
+ }
+
+ TAILQ_REMOVE(&flow->sxe2_flow_list, hw_flow, next);
+ rte_free(hw_flow);
+ }
+ rte_free(flow);
+ *flow_ptr = NULL;
+ rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+ return ret1;
+}
+
+static int32_t sxe2_flow_validate(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct rte_flow *flow_list = NULL;
+ struct sxe2_flow *hw_flow = NULL;
+ struct sxe2_flow *hw_flow_temp = NULL;
+ flow_list = rte_zmalloc("rte_flow_va", sizeof(*flow_list), 0);
+ if (!flow_list) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ TAILQ_INIT(&flow_list->sxe2_flow_list);
+
+ ret = sxe2_flow_validate_with_flow(dev, flow_list, attr, pattern, actions, error);
+ if (ret != 0)
+ goto l_free;
+l_free:
+
+ TAILQ_FOREACH_SAFE(hw_flow, &flow_list->sxe2_flow_list, next, hw_flow_temp) {
+ TAILQ_REMOVE(&flow_list->sxe2_flow_list, hw_flow, next);
+ rte_free(hw_flow);
+ }
+ rte_free(flow_list);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_isolate(struct rte_eth_dev *dev,
+ int32_t enable,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (dev->data->dev_started) {
+ rte_flow_error_set(error, EBUSY,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "port must be stopped first");
+ ret = -EBUSY;
+ goto l_end;
+ }
+
+ if (adapter->is_dev_repr) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "representor dev cannot change isolated mode ");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (enable == adapter->flow_isolated)
+ goto l_end;
+
+ if (adapter->dev_type == SXE2_DEV_T_VF &&
+ adapter->switchdev_info.is_switchdev) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "isolated mode cannot be change when port in switch dev mode");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+ if (!TAILQ_EMPTY(&adapter->flow_ctxt.rte_flow_list))
+ PMD_DEV_LOG_WARN(adapter, DRV,
+ "The configured flow item may not take effect.");
+ rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+ adapter->flow_isolated = !!enable;
+
+ ret = sxe2_l2_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+ ret = sxe2_switchdev_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+ if (ret == 0)
+ adapter->flow_isolate_cfg = !!enable;
+ return ret;
+}
+
+static struct rte_flow *sxe2_flow_create(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action action[],
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_flow *flow_list = NULL;
+ struct sxe2_flow *flow = NULL;
+
+ flow_list = rte_zmalloc("sxe2_flow_create", sizeof(*flow_list), 0);
+ if (!flow_list) {
+ rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to alloc memory for flow rule");
+ PMD_LOG_ERR(DRV, "Failed to alloc memory for flow rule.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ TAILQ_INIT(&flow_list->sxe2_flow_list);
+
+ ret = sxe2_flow_validate_with_flow(dev, flow_list, attr, pattern, action, error);
+ if (ret != 0)
+ goto l_free_flow;
+
+ TAILQ_FOREACH(flow, &flow_list->sxe2_flow_list, next) {
+ ret = sxe2_fnav_get_filter_cid(adapter, flow);
+ if (ret != 0) {
+ PMD_LOG_ERR(DRV, "fnav get stats id failed, ret:%d", ret);
+ rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "Failed to add fnav rule:alloc cid failed.");
+ goto l_free_flow;
+ }
+ ret = sxe2_drv_flow_filter_add(adapter, flow);
+ if (ret) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+ "Failed to add flow filter to hw.");
+ PMD_LOG_ERR(DRV, "Failed to add flow filter to hw.ret:%d:%s",
+ ret, sxe2_flow_convert_ret_to_flow_msg(ret));
+ goto l_free_flow;
+ }
+ }
+
+ TAILQ_INSERT_TAIL(&adapter->flow_ctxt.rte_flow_list, flow_list, next);
+ goto l_end;
+l_free_flow:
+ (void)sxe2_flow_rte_list_free(adapter, &flow_list, error);
+l_end:
+ return flow_list;
+}
+
+static int32_t sxe2_flow_destroy(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ ret = sxe2_flow_rte_list_free(adapter, &flow, error);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to destroy flow.ret:%d.", ret);
+ return ret;
+}
+
+static int32_t sxe2_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_flow *flow = NULL;
+ struct rte_flow *tmp_flow = NULL;
+ struct rte_flow_list_t *flow_list = &adapter->flow_ctxt.rte_flow_list;
+ TAILQ_FOREACH_SAFE(flow, flow_list, next, tmp_flow) {
+ ret = sxe2_flow_destroy(dev, flow, error);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to flush flows.ret:%d.", ret);
+
+ if (ret != -EAGAIN)
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_fnav_get_filter_cid(struct sxe2_adapter *adapter, struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+ &adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+ uint32_t stat_index;
+ uint32_t user_id;
+ uint32_t driver_id;
+ struct sxe2_fnav_cid_mgr *temp = NULL;
+ struct sxe2_fnav_cid_mgr *mgr = NULL;
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types)) {
+ user_id = flow->action.count.user_id;
+ driver_id = flow->action.count.driver_id;
+
+ TAILQ_FOREACH(temp, cid_mgr_list, next) {
+ if (temp->user_id == user_id &&
+ temp->driver_id == driver_id) {
+ mgr = temp;
+ break;
+ }
+ }
+ if (mgr == NULL) {
+ mgr = rte_zmalloc("sxe2_fnav_cid_mgr",
+ sizeof(struct sxe2_fnav_cid_mgr), 0);
+ if (!mgr) {
+ PMD_LOG_ERR(DRV,
+ "Failed to alloc sxe2vf_fnav_cid_mgr memory.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ ret = sxe2_drv_flow_fnav_get_stat_id(adapter, &stat_index);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to alloc fw count id.");
+ rte_free(mgr);
+ goto l_end;
+ }
+
+ TAILQ_INSERT_TAIL(cid_mgr_list, mgr, next);
+ mgr->user_id = user_id;
+ mgr->driver_id = driver_id;
+ mgr->stat_index = stat_index;
+ mgr->count_type = adapter->flow_ctxt.hw_res.count_type;
+ }
+ flow->action.count.stat_index = mgr->stat_index;
+ flow->action.count.stat_ctrl = mgr->count_type;
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_flow_free_mgr(struct sxe2_adapter *adapter,
+ struct sxe2_flow *flow,
+ struct sxe2_fnav_cid_mgr **mgr_ptr,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+ &adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+ struct sxe2_fnav_cid_mgr *mgr = *mgr_ptr;
+ uint32_t user_id = flow->action.count.user_id;
+ if (user_id == 0) {
+ TAILQ_REMOVE(cid_mgr_list, mgr, next);
+ ret = sxe2_drv_flow_fnav_free_stat(adapter, mgr->stat_index);
+ if (ret) {
+ rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to free flow count.");
+ PMD_LOG_ERR(DRV,
+ "Failed to free flow count, flow id: %u, ret: %d.",
+ flow->flow_id, ret);
+ }
+ rte_free(mgr);
+ *mgr_ptr = NULL;
+ }
+ return ret;
+}
+
+int32_t sxe2_flow_query_mgr(struct sxe2_adapter *adapter,
+ struct sxe2_flow *flow,
+ struct sxe2_fnav_cid_mgr **mgr_ptr,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+ &adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+ struct sxe2_fnav_cid_mgr *temp = NULL;
+ struct sxe2_fnav_cid_mgr *mgr = NULL;
+ uint32_t user_id = flow->action.count.user_id;
+ uint32_t driver_id = flow->action.count.driver_id;
+
+ TAILQ_FOREACH(temp, cid_mgr_list, next) {
+ if (temp->user_id == user_id &&
+ temp->driver_id == driver_id) {
+ mgr = temp;
+ break;
+ }
+ }
+ if (!mgr) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "fnav flow query count invalid user_id or driver_id.");
+ PMD_LOG_ERR(DRV,
+ "fnav flow query count invalid user_id or driver_id.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ ret = sxe2_drv_flow_fnav_query_stat(adapter, mgr);
+ if (ret) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+ "Failed to query flow count.");
+ PMD_LOG_ERR(DRV,
+ "Failed to query flow count, flow id: %u, ret: %d.",
+ flow->flow_id, ret);
+ goto l_end;
+ }
+ *mgr_ptr = mgr;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_query_count(struct sxe2_adapter *adapter,
+ struct sxe2_flow *flow,
+ struct rte_flow_query_count *count,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_fnav_cid_mgr *mgr = NULL;
+ switch (flow->action.count.stat_ctrl) {
+ case SXE2_FNAV_STAT_ENA_NONE:
+ count->hits_set = 0;
+ count->bytes_set = 0;
+ break;
+ case SXE2_FNAV_STAT_ENA_PKTS:
+ count->hits_set = 1;
+ count->bytes_set = 0;
+ break;
+ case SXE2_FNAV_STAT_ENA_BYTES:
+ count->hits_set = 0;
+ count->bytes_set = 1;
+ break;
+ case SXE2_FNAV_STAT_ENA_ALL:
+ count->hits_set = 1;
+ count->bytes_set = 1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (!sxe2_test_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types)) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "this flow don't have count action.");
+ PMD_LOG_ERR(DRV, "this flow don't have count action.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ ret = sxe2_flow_query_mgr(adapter, flow, &mgr, error);
+ if (ret) {
+ PMD_LOG_ERR(DRV,
+ "Failed to query flow count, flow id: %u, ret: %d.",
+ flow->flow_id, ret);
+ goto l_end;
+ }
+ count->hits = mgr->hits;
+ count->bytes = mgr->bytes;
+ if (count->reset) {
+ mgr->hits = 0;
+ mgr->bytes = 0;
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_query(struct rte_eth_dev *dev,
+ struct rte_flow *flow_list,
+ const struct rte_flow_action *actions,
+ void *data,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct rte_flow_query_count *count = data;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_flow *flow = NULL;
+
+ if (!flow_list) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "Invalid flow");
+ PMD_LOG_ERR(DRV, "Invalid flow to query flow.");
+ goto l_end;
+ }
+
+ rte_spinlock_lock(&adapter->flow_ctxt.flow_list_lock);
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_VOID:
+ break;
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ flow = TAILQ_FIRST(&flow_list->sxe2_flow_list);
+ ret = sxe2_flow_query_count(adapter, flow, count, error);
+ if (ret) {
+ PMD_LOG_ERR(DRV,
+ "Failed to query flow count, flow id: %u, ret: %d.",
+ flow->flow_id, ret);
+ goto l_end_unlock;
+ }
+ break;
+ default:
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ actions,
+ "action not supported");
+ PMD_LOG_ERR(DRV,
+ "Failed to query flow action type:%d.",
+ actions->type);
+ ret = -ENOTSUP;
+ goto l_end_unlock;
+ }
+ }
+
+l_end_unlock:
+ rte_spinlock_unlock(&adapter->flow_ctxt.flow_list_lock);
+
+l_end:
+ return ret;
+}
+
+const struct rte_flow_ops sxe2_flow_ops = {
+ .validate = sxe2_flow_validate,
+ .create = sxe2_flow_create,
+ .destroy = sxe2_flow_destroy,
+ .flush = sxe2_flow_flush,
+ .query = sxe2_flow_query,
+ .isolate = sxe2_flow_isolate,
+};
+
+int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops)
+{
+ int32_t ret = 0;
+
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ *ops = &sxe2_flow_ops;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_flow_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ TAILQ_INIT(&adapter->flow_ctxt.rte_flow_list);
+ TAILQ_INIT(&adapter->flow_ctxt.hw_res.fnav_cid_mgr_list);
+ if (adapter->devargs.fnav_stat_type)
+ adapter->flow_ctxt.hw_res.count_type =
+ adapter->devargs.fnav_stat_type;
+ else
+ adapter->flow_ctxt.hw_res.count_type = SXE2_FNAV_STAT_ENA_ALL;
+
+ adapter->flow_ctxt.fnav_inited = 1;
+ rte_spinlock_init(&adapter->flow_ctxt.flow_list_lock);
+ return ret;
+}
+
+int32_t sxe2_flow_uninit(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_flow_error error;
+ struct sxe2_fnav_cid_mgr *mgr = NULL;
+ struct sxe2_fnav_cid_mgr *temp = NULL;
+ struct sxe2_fnav_cid_mgr_list_t *cid_mgr_list =
+ &adapter->flow_ctxt.hw_res.fnav_cid_mgr_list;
+
+ ret = sxe2_flow_flush(dev, &error);
+ if (ret)
+ PMD_LOG_ERR(DRV, "Failed to flush flow, ret: %d.", ret);
+
+ TAILQ_FOREACH_SAFE(mgr, cid_mgr_list, next, temp) {
+ TAILQ_REMOVE(cid_mgr_list, mgr, next);
+ ret = sxe2_drv_flow_fnav_free_stat(adapter, mgr->stat_index);
+ if (ret)
+ PMD_LOG_ERR(DRV,
+ "Failed to free fnav stat id, ret: %d.", ret);
+ rte_free(mgr);
+ }
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow.h b/drivers/net/sxe2/sxe2_flow.h
new file mode 100644
index 0000000000..9970fddcf0
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_FLOW_H__
+#define __SXE2_FLOW_H__
+#include <rte_flow_driver.h>
+#include "sxe2_osal.h"
+#include "sxe2_common.h"
+
+
+int32_t sxe2_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops);
+
+int32_t sxe2_flow_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_flow_uninit(struct rte_eth_dev *dev);
+
+int32_t sxe2_fnav_get_filter_cid(struct sxe2_adapter *adapter, struct sxe2_flow *flow);
+
+int32_t sxe2_flow_free_mgr(struct sxe2_adapter *adapter,
+ struct sxe2_flow *flow,
+ struct sxe2_fnav_cid_mgr **mgr_ptr,
+ struct rte_flow_error *error);
+
+int32_t sxe2_flow_query_mgr(struct sxe2_adapter *adapter,
+ struct sxe2_flow *flow,
+ struct sxe2_fnav_cid_mgr **mgr_ptr,
+ struct rte_flow_error *error);
+#endif /* __SXE2_FLOW_H__ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_action.c b/drivers/net/sxe2/sxe2_flow_parse_action.c
new file mode 100644
index 0000000000..a9559e2d7e
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_action.c
@@ -0,0 +1,1182 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_common_log.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_vsi.h"
+
+
+static int32_t sxe2_flow_check_rss_action_attr(const struct rte_flow_action_rss *rss,
+ struct rte_flow_error *error)
+{
+ int32_t ret = ENOTSUP;
+ switch (rss->func) {
+ case RTE_ETH_HASH_FUNCTION_DEFAULT:
+ case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+ case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ:
+ case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "RSS hash function[%d] not support.", rss->func);
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (rss->level > 2)
+ rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "RSS level is could not be greater than 2");
+ if (rss->key_len)
+ rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "a nonzero RSS key_len is not supported");
+ if (rss->queue_num)
+ rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "a non-NULL RSS queue is not supported");
+ ret = 0;
+l_end:
+ return ret;
+}
+
+
+static int32_t sxe2_flow_set_rss_action_func(enum rte_eth_hash_function rss_func,
+ uint64_t rss_type,
+ struct sxe2_flow *flow,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ if (rss_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+ if (flow->has_hdr) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, -EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to cfg Simple XOR hash with not empty pattern");
+ PMD_LOG_ERR(DRV, "Failed to cfg Simple XOR hash with not empty pattern.");
+ goto l_end;
+ }
+ } else {
+ if (!flow->has_hdr) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, -EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to cfg Simple hash with empty pattern");
+ PMD_LOG_ERR(DRV, "Failed to cfg Simple hash with empty pattern.");
+ goto l_end;
+ }
+ }
+
+ if (rss_func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+ if (rss_type & (RTE_ETH_RSS_L3_SRC_ONLY |
+ RTE_ETH_RSS_L3_DST_ONLY |
+ RTE_ETH_RSS_L4_SRC_ONLY |
+ RTE_ETH_RSS_L4_DST_ONLY)) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, -EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to cfg symm func rss_type l3/l4 only.");
+ PMD_LOG_ERR(DRV, "Failed to cfg symm func rss_type l3/l4 only.");
+ goto l_end;
+ }
+
+ if (!(rss_type & (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 |
+ RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP))) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, -EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to cfg symm func unsupported rss_type.");
+ PMD_LOG_ERR(DRV, "Failed to cfg symm func unsupported rss_type.");
+ goto l_end;
+ }
+ flow->action.rss.func = SXE2_RSS_HASH_FUNC_SYM_TOEPLITZ;
+ }
+ if (rss_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
+ flow->action.rss.func = SXE2_RSS_HASH_FUNC_XOR;
+ if (rss_func == RTE_ETH_HASH_FUNCTION_DEFAULT)
+ flow->action.rss.func = SXE2_RSS_HASH_FUNC_TOEPLITZ;
+ if (rss_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ)
+ flow->action.rss.func = SXE2_RSS_HASH_FUNC_TOEPLITZ;
+l_end:
+ return ret;
+}
+
+
+static uint64_t sxe2_hash_invalid_comb[] = {
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_UDP,
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP,
+ RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_SCTP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_UDP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_TCP,
+ RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_SCTP,
+ RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER,
+ RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER,
+ RTE_ETH_RSS_L3_PRE32 | RTE_ETH_RSS_L3_PRE48 | RTE_ETH_RSS_L3_PRE64,
+};
+
+struct sxe2_rss_attr_type {
+ uint64_t attr;
+ uint64_t type;
+};
+
+static struct sxe2_rss_attr_type sxe2_rss_attr_valid_type[] = {
+ {RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY, RTE_ETH_RSS_ETH},
+ {RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY, SXE2_VALID_RSS_L3},
+ {RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY, SXE2_VALID_RSS_L4},
+
+ {RTE_ETH_RSS_L3_PRE32, SXE2_VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE48, SXE2_VALID_RSS_IPV6},
+ {RTE_ETH_RSS_L3_PRE64, SXE2_VALID_RSS_IPV6},
+ {SXE2_INVALID_RSS_ATTR, 0}
+};
+
+
+static void sxe2_flow_action_pre(struct sxe2_flow *flow)
+{
+ flow->action.vsi.vsi_index = UINT16_MAX;
+ flow->action.vsi_list.vsi_cnt = 0;
+ sxe2_bitmap_zero(flow->action.vsi_list.vsi_list_map, SXE2_VSI_MAX);
+}
+
+static void sxe2_flow_action_post(struct sxe2_flow *flow, uint8_t action_num[])
+{
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types))
+ action_num[SXE2_FLOW_ACTION_TO_VSI] = 1;
+
+ if (sxe2_test_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types))
+ action_num[SXE2_FLOW_ACTION_TO_VSI_LIST] = 1;
+}
+
+
+static void sxe2_flow_action_vsi_merge(struct sxe2_flow *flow, uint16_t add_vsi_id)
+{
+ if (flow->action.vsi_list.vsi_cnt == 0) {
+ if (flow->action.vsi.vsi_index == UINT16_MAX) {
+ flow->action.vsi.vsi_index = add_vsi_id;
+ sxe2_set_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types);
+ goto l_end;
+ }
+
+ if (flow->action.vsi.vsi_index == add_vsi_id)
+ goto l_end;
+
+ sxe2_set_bit(flow->action.vsi.vsi_index, flow->action.vsi_list.vsi_list_map);
+ sxe2_set_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map);
+ flow->action.vsi_list.vsi_cnt = 2;
+ flow->action.vsi.vsi_index = UINT16_MAX;
+ sxe2_clear_bit(SXE2_FLOW_ACTION_TO_VSI, flow->action.act_types);
+ sxe2_set_bit(SXE2_FLOW_ACTION_TO_VSI_LIST, flow->action.act_types);
+ }
+
+ if (sxe2_test_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map))
+ goto l_end;
+
+ sxe2_set_bit(add_vsi_id, flow->action.vsi_list.vsi_list_map);
+ flow->action.vsi_list.vsi_cnt++;
+
+l_end:
+ return;
+}
+
+
+static int32_t sxe2_flow_vsi_get_ethdev(struct rte_eth_dev *dev,
+ uint16_t dev_port_id, uint16_t *vsi_index)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_eth_dev *dst_dev;
+ struct sxe2_adapter *dst_adapter;
+ int32_t ret = 0;
+
+ dst_dev = &rte_eth_devices[dev_port_id];
+ if (!dst_dev->data) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!sxe2_ethdev_check(dst_dev)) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "dst dev is not sxe2 ethdev.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ dst_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dst_dev);
+ if (!dst_adapter) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "dst dev adapter is null.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (adapter->dev_info.pci.serial_number != dst_adapter->dev_info.pci.serial_number) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "dst dev sn is miss match current dev.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (adapter->dev_type != SXE2_DEV_T_PF_BOND) {
+ if (adapter->pf_idx != dst_adapter->pf_idx) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "dst dev pf id is miss match current dev.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+ if (dst_adapter->is_dev_repr) {
+ if (dst_adapter->repr_priv_data == NULL) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "dst dev repr data is null.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ *vsi_index = dst_adapter->repr_priv_data->repr_vf_vsi_id;
+ } else {
+ *vsi_index = dst_adapter->vsi_ctxt.dpdk_vsi_id;
+ }
+
+l_end:
+ return ret;
+}
+static int32_t sxe2_flow_check_rss_action_type_with_pattern(struct sxe2_flow_pattern *pattern,
+ uint64_t rss_type)
+{
+ uint64_t rss_type_allow = pattern->rss_type_allow;
+ int32_t ret = -EINVAL;
+
+ if ((rss_type & rss_type_allow) != rss_type)
+ goto l_end;
+
+ if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs) &&
+ !sxe2_test_bit(SXE2_FLOW_HDR_QINQ, pattern->hdrs)) {
+ if ((rss_type & RTE_ETH_RSS_C_VLAN) != 0 &&
+ (rss_type & RTE_ETH_RSS_S_VLAN) == 0)
+ goto l_end;
+ }
+ ret = 0;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_rss_action_type_valid(uint64_t rss_type)
+{
+ struct sxe2_rss_attr_type *attr_type;
+ uint32_t i;
+ int32_t ret = -EINVAL;
+
+ for (i = 0; i < RTE_DIM(sxe2_hash_invalid_comb); i++) {
+ if (rte_popcount64(rss_type & sxe2_hash_invalid_comb[i]) > 1) {
+ PMD_LOG_ERR(DRV, "Error rss_type invalid comb[%d].", i);
+ goto l_end;
+ }
+ }
+
+ for (i = 0; i < RTE_DIM(sxe2_rss_attr_valid_type); i++) {
+ attr_type = &sxe2_rss_attr_valid_type[i];
+ if ((attr_type->attr & rss_type) &&
+ !(attr_type->type & rss_type)) {
+ PMD_LOG_ERR(DRV, "Rss_type valid_comb[%d] check error.", i);
+ goto l_end;
+ }
+ }
+
+ ret = 0;
+l_end:
+ return ret;
+}
+
+
+static void sxe2_flow_set_rss_action_type_l234(BITMAP_TYPE *hdr,
+ BITMAP_TYPE *fld,
+ uint64_t rss_type)
+{
+ if (rss_type & RTE_ETH_RSS_ETH) {
+ if (rss_type & RTE_ETH_RSS_L2_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L2_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, fld);
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_L2_PAYLOAD) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, fld);
+ sxe2_set_bit(SXE2_FLOW_HDR_ETH_NON_IP, hdr);
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, hdr)) {
+ if (rss_type & RTE_ETH_RSS_S_VLAN)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, fld);
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_QINQ, hdr)) {
+ if (rss_type & RTE_ETH_RSS_C_VLAN)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, fld);
+ }
+
+ if (rss_type & (RTE_ETH_RSS_IPV4 |
+ RTE_ETH_RSS_NONFRAG_IPV4_OTHER |
+ RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+ RTE_ETH_RSS_FRAG_IPV4 |
+ RTE_ETH_RSS_IPV4_CHKSUM)) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, fld);
+ }
+
+ if (rss_type & RTE_ETH_RSS_NONFRAG_IPV4_OTHER)
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, hdr);
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV4) {
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, hdr);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_ID, fld);
+ }
+
+ if (rss_type & RTE_ETH_RSS_IPV4_CHKSUM)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_CHKSUM, fld);
+ }
+
+ if (rss_type & (RTE_ETH_RSS_IPV6 |
+ RTE_ETH_RSS_FRAG_IPV6 |
+ RTE_ETH_RSS_NONFRAG_IPV6_OTHER |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_L3_PRE32) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE32_DA, fld);
+ }
+ } else if (rss_type & RTE_ETH_RSS_L3_PRE48) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE48_DA, fld);
+ }
+ } else if (rss_type & RTE_ETH_RSS_L3_PRE64) {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PRE64_DA, fld);
+ }
+ } else {
+ if (rss_type & RTE_ETH_RSS_L3_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, fld);
+ } else if (rss_type & RTE_ETH_RSS_L3_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, fld);
+ }
+ }
+ if (rss_type & RTE_ETH_RSS_FRAG_IPV6) {
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, hdr);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_ID, fld);
+ }
+ if (rss_type & RTE_ETH_RSS_NONFRAG_IPV6_OTHER)
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_OTHER, hdr);
+ }
+
+ if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_TCP |
+ RTE_ETH_RSS_NONFRAG_IPV6_TCP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, fld);
+ } else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, fld);
+ }
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_CHKSUM, fld);
+ }
+
+ if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+ RTE_ETH_RSS_NONFRAG_IPV6_UDP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, fld);
+ } else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, fld);
+ }
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_CHKSUM, fld);
+ }
+
+ if (rss_type & (RTE_ETH_RSS_NONFRAG_IPV4_SCTP |
+ RTE_ETH_RSS_NONFRAG_IPV6_SCTP)) {
+ if (rss_type & RTE_ETH_RSS_L4_SRC_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, fld);
+ } else if (rss_type & RTE_ETH_RSS_L4_DST_ONLY) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, fld);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, fld);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, fld);
+ }
+ if (rss_type & RTE_ETH_RSS_L4_CHKSUM)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_CHKSUM, fld);
+ }
+}
+
+
+static int32_t sxe2_flow_set_rss_action_hdr_type(struct sxe2_flow *flow,
+ bool is_inner)
+{
+ struct sxe2_flow_action_rss *rss = &flow->action.rss;
+ BITMAP_TYPE *hdr = rss->hdr_out;
+ int32_t ret = 0;
+
+ rss->hdr_type = SXE2_RSS_ANY_HEADERS;
+ if (!is_inner) {
+ rss->hdr_type = SXE2_RSS_OUTER_HEADERS;
+ goto l_end;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, hdr)) {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, hdr)) {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GRE;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GENEVE;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_VXLAN;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_UDP_GTPU;
+ }
+ } else {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4_GRE;
+ } else {
+ rss->hdr_type = SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV4;
+ }
+ }
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, hdr)) {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, hdr)) {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GRE;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GENEVE;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_VXLAN;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_UDP_GTPU;
+ }
+ } else {
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, hdr)) {
+ rss->hdr_type =
+ SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6_GRE;
+ } else {
+ rss->hdr_type = SXE2_RSS_INNER_HEADERS_WITH_OUTER_IPV6;
+ }
+ }
+ }
+
+l_end:
+ if (rss->hdr_type == SXE2_RSS_ANY_HEADERS) {
+ ret = -EINVAL;
+ PMD_LOG_ERR(DRV, "Unsupported rss hdr type.");
+ }
+ return ret;
+}
+
+static int32_t sxe2_flow_set_rss_action_level(uint32_t level,
+ struct sxe2_flow *flow, struct rte_flow_error *error)
+{
+ bool is_inner = false;
+ struct sxe2_flow_action_rss *rss = &flow->action.rss;
+ int32_t ret = 0;
+
+ if (flow->meta.tunnel_type != SXE2_FLOW_TUNNEL_TYPE_NONE) {
+ if (level == 0 || level == 2)
+ is_inner = true;
+ else if (level == 1)
+ is_inner = false;
+ } else {
+ if (level == 2) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "RSS hash level 2 is not allowed no tunnel flow.");
+ PMD_LOG_ERR(DRV, "RSS hash level 2 is not allowed no tunnel flow.");
+ goto l_end;
+ }
+ is_inner = false;
+ }
+ rss->is_inner = is_inner;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_set_rss_action_type(uint64_t rss_type,
+ struct sxe2_flow *flow, struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+ struct sxe2_flow_pattern *pattern = NULL;
+ struct sxe2_flow_action_rss *rss = &flow->action.rss;
+ BITMAP_TYPE *hdr;
+ BITMAP_TYPE *fld;
+ bool is_inner = rss->is_inner;
+
+ ret = sxe2_flow_check_rss_action_type_valid(rss_type);
+ if (ret) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "RSS hash type has invalid combination.");
+ PMD_LOG_ERR(DRV, "RSS hash type has invalid combination.");
+ goto l_end;
+ }
+
+ pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ ret = sxe2_flow_check_rss_action_type_with_pattern(pattern,
+ rss_type);
+ if (ret) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "RSS hash type is not allowed by pattern.");
+ PMD_LOG_ERR(DRV, "RSS hash type is not allowed by pattern.");
+ goto l_end;
+ }
+
+ sxe2_bitmap_copy(rss->hdr_out, flow->pattern_outer.hdrs,
+ SXE2_FLOW_HDR_MAX);
+ sxe2_bitmap_copy(rss->hdr_in, flow->pattern_inner.hdrs,
+ SXE2_FLOW_HDR_MAX);
+ hdr = is_inner ? rss->hdr_in : rss->hdr_out;
+ fld = rss->fld;
+ sxe2_flow_set_rss_action_type_l234(hdr, fld, rss_type);
+
+ ret = sxe2_flow_set_rss_action_hdr_type(flow, is_inner);
+ if (ret) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Unsupported rss hdr type.");
+ PMD_LOG_ERR(DRV, "Unsupported rss hdr type.");
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_action_rss(const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ const struct rte_flow_action_rss *rss = action->conf;
+ int32_t ret = 0;
+ uint64_t rss_type = rss->types;
+ enum rte_eth_hash_function rss_func = rss->func;
+ uint32_t level = rss->level;
+
+ rss_type = rte_eth_rss_hf_refine(rss_type);
+
+ ret = sxe2_flow_check_rss_action_attr(rss, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_set_rss_action_func(rss_func, rss_type, flow, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_set_rss_action_level(level, flow, error);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_flow_set_rss_action_type(rss_type, flow, error);
+ if (ret)
+ goto l_end;
+ sxe2_set_bit(SXE2_FLOW_ACTION_RSS, flow->action.act_types);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_action_qregion(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error, struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ uint8_t i = 0;
+ const struct rte_flow_action_rss *rss = action->conf;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (rss->types != 0 || rss->key_len != 0) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Queue region not support rss types or key.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (rss->queue_num <= 1) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Queue region size can't be 0 or 1.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ for (i = 0; i < rss->queue_num - 1; i++) {
+ if (rss->queue[i + 1] != rss->queue[i] + 1) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Queue index for queue region is not continuous.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ if (rss->queue[rss->queue_num - 1] >= adapter->dev_info.dev_data->nb_rx_queues) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Queue index for queue region is out of range.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!(rte_is_power_of_2(rss->queue_num))) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Queue region size must be power of 2.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ flow->action.q_region.vsi_index = adapter->vsi_ctxt.dpdk_vsi_id;
+ flow->action.q_region.q_index = rss->queue[0];
+ flow->action.q_region.region = (uint8_t)rte_log2_u32(rss->queue_num);
+ sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types);
+l_end:
+ return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_queue(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ const struct rte_flow_action_queue *queue = action->conf;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (queue->index >= adapter->dev_info.dev_data->nb_rx_queues) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid queue index.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ flow->action.queue.vsi_index = adapter->vsi_ctxt.dpdk_vsi_id;
+ flow->action.queue.q_index = queue->index;
+ sxe2_set_bit(SXE2_FLOW_ACTION_QUEUE, flow->action.act_types);
+l_end:
+ return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_represented_port(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ const struct rte_flow_action_ethdev *action_ethdev_conf;
+ const struct rte_eth_dev *dst_repr_dev;
+ uint16_t dst_repr_vsi_id;
+ uint16_t dst_backer_port_id;
+ uint16_t src_backer_port_id;
+ int32_t ret = 0;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Represented port action only support in switchdev mode.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (adapter->dev_type == SXE2_DEV_T_VF) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Failed to cfg vf dev type.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ action_ethdev_conf = action->conf;
+ if (!rte_eth_dev_is_valid_port(action_ethdev_conf->port_id)) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid port for represented port action.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ dst_repr_dev = &rte_eth_devices[action_ethdev_conf->port_id];
+ if (!dst_repr_dev->data) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid port for represented port action.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ dst_backer_port_id = dst_repr_dev->data->backer_port_id;
+ if (adapter->is_dev_repr)
+ src_backer_port_id = dev->data->backer_port_id;
+ else
+ src_backer_port_id = adapter->dev_port_id;
+
+ if (src_backer_port_id != dst_backer_port_id) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Represented port action only support to cfg port in same device.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_flow_vsi_get_ethdev(dev, action_ethdev_conf->port_id, &dst_repr_vsi_id);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Port representor action port dev invalid.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ sxe2_flow_action_vsi_merge(flow, dst_repr_vsi_id);
+l_end:
+ return ret;
+}
+
+
+static int32_t sxe2_flow_parse_action_port_representor(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ const struct rte_flow_action_ethdev *action_ethdev_conf;
+ uint16_t dst_vsi_id;
+ int32_t ret = 0;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Port representor action only support in switchdev mode.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (adapter->dev_type == SXE2_DEV_T_VF) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Cfg rule dev type is vf.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!adapter->is_dev_repr) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Cfg rule dev type is not repr.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ action_ethdev_conf = action->conf;
+ if (!action_ethdev_conf || !rte_eth_dev_is_valid_port(action_ethdev_conf->port_id)) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid port for port representor action.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (dev->data->backer_port_id != action_ethdev_conf->port_id) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid port for port representor.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_flow_vsi_get_ethdev(dev, action_ethdev_conf->port_id, &dst_vsi_id);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Port representor action port dev invalid.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ sxe2_flow_action_vsi_merge(flow, dst_vsi_id);
+l_end:
+ return ret;
+}
+
+int32_t sxe2_flow_parse_action_port_id(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ const struct rte_flow_action_port_id *action_port_id_conf;
+ uint16_t dst_port_id;
+ uint16_t dst_vsi_id;
+ int32_t ret = 0;
+
+ action_port_id_conf = (const struct rte_flow_action_port_id *)action->conf;
+ dst_port_id = action_port_id_conf->original ?
+ adapter->dev_port_id : action_port_id_conf->id;
+
+ if (!rte_eth_dev_is_valid_port(dst_port_id)) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+ action, "Invalid port id.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_flow_vsi_get_ethdev(dev, dst_port_id, &dst_vsi_id);
+ if (ret != 0) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Failed to cfg port dev invalid.");
+ goto l_end;
+ }
+
+ sxe2_flow_action_vsi_merge(flow, dst_vsi_id);
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_action_send_to_kernel(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action, struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ if (adapter->vsi_ctxt.kernel_vsi_id == UINT16_MAX) {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Failed to cfg send to kernel action without kernel vsi.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ sxe2_flow_action_vsi_merge(flow, adapter->vsi_ctxt.kernel_vsi_id);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_flow_check_actions(struct rte_eth_dev *dev __rte_unused, struct sxe2_flow *flow,
+ uint8_t action_num[], struct rte_flow_error *error)
+{
+ enum sxe2_flow_engine_type engine_type = flow->engine_type;
+ int32_t ret = 0;
+ int32_t dest_num = action_num[SXE2_FLOW_ACTION_Q_REGION] +
+ action_num[SXE2_FLOW_ACTION_QUEUE];
+ int32_t vsi_num = action_num[SXE2_FLOW_ACTION_TO_VSI];
+ int32_t vsi_list_num = action_num[SXE2_FLOW_ACTION_TO_VSI_LIST];
+ int32_t pass_num = action_num[SXE2_FLOW_ACTION_PASSTHRU];
+ int32_t drop_num = action_num[SXE2_FLOW_ACTION_DROP];
+ int32_t mark_num = action_num[SXE2_FLOW_ACTION_MARK];
+ int32_t count_num = action_num[SXE2_FLOW_ACTION_COUNT];
+ int32_t rss_num = action_num[SXE2_FLOW_ACTION_RSS];
+ int32_t fwd_num = dest_num + vsi_num + vsi_list_num;
+ int32_t total_num = dest_num + vsi_num + vsi_list_num + pass_num +
+ drop_num + mark_num + count_num + rss_num;
+
+ if (pass_num > 1 || drop_num > 1 || mark_num > 1 ||
+ count_num > 1 || rss_num > 1 || dest_num > 1 ||
+ vsi_num > 1 || vsi_list_num > 1) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "ecah action can only be used once.");
+ PMD_LOG_ERR(DRV, "ecah action can only be used once.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (vsi_list_num && engine_type != SXE2_FLOW_ENGINE_SWITCH) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "VSI_LIST action is only supported for switch engine.");
+ PMD_LOG_ERR(DRV, "VSI_LIST action is only supported for switch engine.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (drop_num) {
+ if (total_num > drop_num + count_num) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Drop action can't be used with other actions unless count.");
+ PMD_LOG_ERR(DRV,
+ "Drop action can't be used with other actions unless count.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+ if (fwd_num > 1) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "Only supports one type of forwarding action.");
+ PMD_LOG_ERR(DRV, "Only supports one type of forwarding action.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (vsi_list_num) {
+ if (total_num > vsi_list_num) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "VSI_LIST action can't be used with other actions.");
+ PMD_LOG_ERR(DRV,
+ "VSI_LIST action can't be used with other actions.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+ if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ if (vsi_num) {
+ flow->action.q_region.q_index = 0;
+ flow->action.q_region.region = 7;
+ flow->action.q_region.vsi_index = flow->action.vsi.vsi_index;
+ sxe2_set_bit(SXE2_FLOW_ACTION_Q_REGION, flow->action.act_types);
+ dest_num++;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+
+int32_t sxe2_flow_parse_action(struct rte_eth_dev *dev,
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ const struct rte_flow_action *action;
+ const struct rte_flow_action_count *act_count;
+ const struct rte_flow_action_mark *act_mark;
+ uint8_t action_num[SXE2_FLOW_ACTION_MAX] = {0};
+ enum sxe2_flow_engine_type engine_type = flow->engine_type;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ sxe2_flow_action_pre(flow);
+
+ for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+ switch (action->type) {
+ case RTE_FLOW_ACTION_TYPE_VOID:
+ break;
+ case RTE_FLOW_ACTION_TYPE_PASSTHRU:
+ if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ sxe2_set_bit(SXE2_FLOW_ACTION_PASSTHRU, flow->action.act_types);
+ action_num[SXE2_FLOW_ACTION_PASSTHRU]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Passthru action is not supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "Passthru action is not supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_DROP:
+ if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+ engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+ engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ sxe2_set_bit(SXE2_FLOW_ACTION_DROP, flow->action.act_types);
+ action_num[SXE2_FLOW_ACTION_DROP]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Drop action is not supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "Drop action is not supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_MARK:
+ if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ sxe2_set_bit(SXE2_FLOW_ACTION_MARK, flow->action.act_types);
+ act_mark = action->conf;
+ flow->action.mark.mark_id = act_mark->id;
+ action_num[SXE2_FLOW_ACTION_MARK]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Mark action is not supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "Mark action is not supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_COUNT:
+ if (engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ sxe2_set_bit(SXE2_FLOW_ACTION_COUNT, flow->action.act_types);
+ act_count = action->conf;
+ flow->action.count.user_id = act_count->id;
+ flow->action.count.driver_id = 0;
+ if (flow->action.count.user_id == 0)
+ flow->action.count.driver_id =
+ ++adapter->flow_ctxt.hw_res.global_index;
+ action_num[SXE2_FLOW_ACTION_COUNT]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Count action is not supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "Count action is not supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_RSS:
+ if (engine_type == SXE2_FLOW_ENGINE_RSS) {
+ ret = sxe2_flow_parse_action_rss(action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ action_num[SXE2_FLOW_ACTION_RSS]++;
+ } else if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+ engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+ engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ ret = sxe2_flow_parse_action_qregion(dev, action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ action_num[SXE2_FLOW_ACTION_Q_REGION]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "RSS action is only supported for RSS flow.");
+ PMD_LOG_ERR(DRV,
+ "RSS action is only supported for RSS flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_QUEUE:
+ if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+ engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+ engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ ret = sxe2_flow_parse_action_queue(dev, action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ action_num[SXE2_FLOW_ACTION_QUEUE]++;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "Queue action is not supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "Queue action is not supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+ if (engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ ret = sxe2_flow_parse_action_represented_port(dev,
+ action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "REPRESENTED PORT action is only supported for SWITCH flow.");
+ PMD_LOG_ERR(DRV,
+ "REPRESENTED PORT action is only supported for SWITCH flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
+ if (engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ ret = sxe2_flow_parse_action_port_representor(dev,
+ action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "PORT REPRESENTOR action is only supported for SWITCH flow.");
+ PMD_LOG_ERR(DRV,
+ "PORT REPRESENTOR action is only supported for SWITCH flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_PORT_ID:
+ if (engine_type == SXE2_FLOW_ENGINE_SWITCH ||
+ engine_type == SXE2_FLOW_ENGINE_ACL ||
+ engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ ret = sxe2_flow_parse_action_port_id(dev, action,
+ error, flow);
+ if (ret != 0)
+ goto l_end;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "PORT ID action is only supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "PORT ID action is only supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL:
+ if (engine_type == SXE2_FLOW_ENGINE_ACL ||
+ engine_type == SXE2_FLOW_ENGINE_FNAV ||
+ engine_type == SXE2_FLOW_ENGINE_SWITCH) {
+ ret = sxe2_flow_parse_action_send_to_kernel(dev,
+ action, error, flow);
+ if (ret != 0)
+ goto l_end;
+ } else {
+ rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, action,
+ "SEND TO KERNEL action is only supported for this flow.");
+ PMD_LOG_ERR(DRV,
+ "SEND TO KERNEL action is only supported for this flow.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ break;
+ default:
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, actions,
+ "Invalid action.");
+ PMD_LOG_ERR(DRV, "Invalid action type:%d", actions->type);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+ sxe2_flow_action_post(flow, action_num);
+
+ ret = sxe2_flow_check_actions(dev, flow, action_num, error);
+ if (ret != 0)
+ goto l_end;
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_action.h b/drivers/net/sxe2/sxe2_flow_parse_action.h
new file mode 100644
index 0000000000..479d10a522
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_action.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_ACTION_H_
+#define SXE2_FLOW_PARSE_ACTION_H_
+#include <rte_flow_driver.h>
+
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+
+int32_t sxe2_flow_parse_action(struct rte_eth_dev *dev,
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow);
+
+int32_t sxe2_flow_parse_action_port_id(struct rte_eth_dev *dev,
+ const struct rte_flow_action *action,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow);
+
+#endif /* SXE2_FLOW_PARSE_ACTION_H_ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_engine.c b/drivers/net/sxe2/sxe2_flow_parse_engine.c
new file mode 100644
index 0000000000..09de1b94c4
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_engine.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_engine.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_flow_public.h"
+#include "sxe2_flow_parse_action.h"
+#include "sxe2_common_log.h"
+
+static int32_t sxe2_flow_parse_engine_chk(struct sxe2_flow *flow,
+ struct rte_flow_error *error)
+{
+ int32_t ret = 0;
+
+ if (flow->engine_type == SXE2_FLOW_ENGINE_FNAV) {
+ if (flow->has_mask) {
+ ret = -EINVAL;
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM_MASK, NULL,
+ "FNAV flow doesn't support mask");
+ PMD_LOG_ERR(DRV, "FNAV flow doesn't support mask");
+ goto l_end;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_FLD_ID_S_VID,
+ flow->pattern_outer.map_spec) &&
+ sxe2_test_bit(SXE2_FLOW_FLD_ID_C_VID,
+ flow->pattern_outer.map_spec)) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+ "Can't set double vid,please use tci.");
+ PMD_LOG_ERR(DRV,
+ "Can't set double vid,please use tci.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_flow_parse_engine(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_action actions[],
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ const struct rte_flow_action *action;
+
+ if (flow->has_mask == 0 && flow->has_spec == 0) {
+ flow->engine_type = SXE2_FLOW_ENGINE_RSS;
+ goto l_end;
+ }
+
+ if (attr->group == 1) {
+ flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+ goto l_end;
+ }
+ if (attr->group == 2) {
+ flow->engine_type = SXE2_FLOW_ENGINE_ACL;
+ goto l_end;
+ }
+ if (attr->group == 3) {
+ flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+ goto l_end;
+ }
+
+ if (adapter->is_dev_repr) {
+ flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+ goto l_end;
+ }
+
+ if (adapter->switchdev_info.is_switchdev &&
+ adapter->dev_type == SXE2_DEV_T_VF) {
+ flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+ goto l_end;
+ }
+
+ for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; action++) {
+ switch (action->type) {
+ case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
+ case RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR:
+ case RTE_FLOW_ACTION_TYPE_PORT_ID:
+ flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+ goto l_end;
+ default:
+ break;
+ }
+ }
+
+ if (adapter->switchdev_info.is_switchdev) {
+ flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+ goto l_end;
+ }
+
+ if (adapter->flow_isolated)
+ flow->engine_type = SXE2_FLOW_ENGINE_SWITCH;
+ else
+ flow->engine_type = SXE2_FLOW_ENGINE_FNAV;
+
+l_end:
+ ret = sxe2_flow_parse_engine_chk(flow, error);
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_engine.h b/drivers/net/sxe2/sxe2_flow_parse_engine.h
new file mode 100644
index 0000000000..1485beecb4
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_engine.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_ENGINE_H_
+#define SXE2_FLOW_PARSE_ENGINE_H_
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+int32_t sxe2_flow_parse_engine(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
+ const struct rte_flow_action actions[], struct rte_flow_error *error,
+ struct sxe2_flow *flow);
+#endif /* SXE2_FLOW_PARSE_ENGINE_H_ */
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.c b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
new file mode 100644
index 0000000000..189abb1a33
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.c
@@ -0,0 +1,1822 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include "sxe2_flow_parse_pattern.h"
+#include "rte_common.h"
+#include "rte_flow.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_flow_define.h"
+
+const struct sxe2_flow_expand_node sxe2_support_expansion[SXE2_EXPANSION_MAX] = {
+ [SXE2_EXPANSION_OUTER_ETH] = {
+ .type = RTE_FLOW_ITEM_TYPE_ETH,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "eth",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_VLAN,
+ SXE2_EXPANSION_OUTER_IPV4,
+ SXE2_EXPANSION_OUTER_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_OUTER_VLAN] = {
+ .type = RTE_FLOW_ITEM_TYPE_VLAN,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "vlan",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_QINQ,
+ SXE2_EXPANSION_OUTER_IPV4,
+ SXE2_EXPANSION_OUTER_IPV6,
+ SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_QINQ] = {
+ .type = RTE_FLOW_ITEM_TYPE_VLAN,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "vlan",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_IPV4,
+ SXE2_EXPANSION_OUTER_IPV6,
+ SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_IPV4] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV4,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_IPIP,
+ .is_tunnel = false,
+ .name = "ipv4",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_UDP,
+ SXE2_EXPANSION_OUTER_TCP,
+ SXE2_EXPANSION_OUTER_SCTP,
+ SXE2_EXPANSION_GRE,
+ SXE2_EXPANSION_NVGRE,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_IPV6] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV6,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_IPIP,
+ .is_tunnel = false,
+ .name = "ipv6",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT,
+ SXE2_EXPANSION_OUTER_UDP,
+ SXE2_EXPANSION_OUTER_TCP,
+ SXE2_EXPANSION_OUTER_SCTP,
+ SXE2_EXPANSION_GRE,
+ SXE2_EXPANSION_NVGRE,
+ SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "ipv6_frag_ext",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_UDP] = {
+ .type = RTE_FLOW_ITEM_TYPE_UDP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "udp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_VXLAN,
+ SXE2_EXPANSION_VXLAN_GPE,
+ SXE2_EXPANSION_GENEVE,
+ SXE2_EXPANSION_GTPU,
+ SXE2_EXPANSION_GRE,
+ SXE2_EXPANSION_NVGRE,
+ SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_TCP] = {
+ .type = RTE_FLOW_ITEM_TYPE_TCP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "tcp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_SCTP] = {
+ .type = RTE_FLOW_ITEM_TYPE_SCTP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "sctp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_OUTER_END),
+ },
+ [SXE2_EXPANSION_OUTER_END] = {
+ .type = RTE_FLOW_ITEM_TYPE_END,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE,
+ .is_tunnel = false,
+ .name = "end",
+ .next = SXE2_FLOW_EXPAND_NEXT(0),
+ },
+ [SXE2_EXPANSION_VXLAN] = {
+ .type = RTE_FLOW_ITEM_TYPE_VXLAN,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_VXLAN,
+ .is_tunnel = true,
+ .name = "vxlan",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_VXLAN_GPE] = {
+ .type = RTE_FLOW_ITEM_TYPE_VXLAN_GPE,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_VXLAN,
+ .is_tunnel = true,
+ .name = "vxlan_gpe",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_GRE] = {
+ .type = RTE_FLOW_ITEM_TYPE_GRE,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GRE,
+ .is_tunnel = true,
+ .name = "gre",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_NVGRE] = {
+ .type = RTE_FLOW_ITEM_TYPE_NVGRE,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GRE,
+ .is_tunnel = true,
+ .name = "nvgre",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_GENEVE] = {
+ .type = RTE_FLOW_ITEM_TYPE_GENEVE,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GENEVE,
+ .is_tunnel = true,
+ .name = "geneve",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_ETH,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_GTPU] = {
+ .type = RTE_FLOW_ITEM_TYPE_GTPU,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_GTPU,
+ .is_tunnel = true,
+ .name = "gtpu",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_ETH] = {
+ .type = RTE_FLOW_ITEM_TYPE_ETH,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "eth",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_VLAN,
+ SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_VLAN] = {
+ .type = RTE_FLOW_ITEM_TYPE_VLAN,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "vlan",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_IPV4,
+ SXE2_EXPANSION_IPV6,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_IPV4] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV4,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "ipv4",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_UDP,
+ SXE2_EXPANSION_TCP,
+ SXE2_EXPANSION_SCTP,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_IPV6] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV6,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "ipv6",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_UDP,
+ SXE2_EXPANSION_TCP,
+ SXE2_EXPANSION_SCTP,
+ SXE2_EXPANSION_IPV6_FRAG_EXT,
+ SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_UDP] = {
+ .type = RTE_FLOW_ITEM_TYPE_UDP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "udp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_TCP] = {
+ .type = RTE_FLOW_ITEM_TYPE_TCP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "tcp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_SCTP] = {
+ .type = RTE_FLOW_ITEM_TYPE_SCTP,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "sctp",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_IPV6_FRAG_EXT] = {
+ .type = RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "ipv6_frag_ext",
+ .next = SXE2_FLOW_EXPAND_NEXT(SXE2_EXPANSION_END),
+ },
+ [SXE2_EXPANSION_END] = {
+ .type = RTE_FLOW_ITEM_TYPE_END,
+ .tunnel_type = SXE2_FLOW_TUNNEL_TYPE_PARENT,
+ .is_tunnel = true,
+ .name = "end",
+ .next = SXE2_FLOW_EXPAND_NEXT(0),
+ }
+};
+
+const char *sxe2_flow_type_name[SXE2_FLOW_TYPE_MAX] = {
+ [SXE2_FLOW_MAC_PAY] = "SXE2_FLOW_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_FRAG_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_UDP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_TCP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_SCTP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_FRAG_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_UDP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_TCP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_SCTP_PAY] =
+ "SXE2_FLOW_MAC_IPV4_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_FRAG_PAY] =
+ "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GTPU_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GTPU_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_VLAN_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_VXGEN_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_VXGEN_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV6_UDP_GRE_MAC_IPV6_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV4_SCTP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_FRAG_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_FRAG_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_UDP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_UDP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_TCP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_TCP_PAY",
+ [SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_SCTP_PAY] = "SXE2_FLOW_MAC_IPV4_UDP_GRE_MAC_IPV6_SCTP_PAY",
+};
+#define SXE2_FLOW_TYPE_NAME_MAX_LEN 128
+
+static int32_t sxe2_flow_get_flow_type(struct sxe2_flow *flow)
+{
+ int32_t ret = -EINVAL;
+ uint16_t i = 0;
+ uint16_t len = 0;
+ char flow_type_name[SXE2_FLOW_TYPE_NAME_MAX_LEN] = {0};
+ len = snprintf(flow_type_name, sizeof(flow_type_name), "SXE2_FLOW_");
+ i += len;
+ if (sxe2_test_bit(SXE2_FLOW_HDR_ETH, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "MAC_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "IPV4_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "IPV6_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV_FRAG, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "FRAG_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "UDP_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_TCP, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "TCP_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_SCTP, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "SCTP_");
+ i += len;
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_HDR_VXLAN, flow->pattern_outer.hdrs) ||
+ sxe2_test_bit(SXE2_FLOW_HDR_GENEVE, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "VXGEN_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GRE, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "GRE_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_GTPU, flow->pattern_outer.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "GTPU_");
+ i += len;
+ }
+
+ if (sxe2_test_bit(SXE2_FLOW_HDR_ETH, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "MAC_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "VLAN_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "IPV4_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "IPV6_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV_FRAG, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "FRAG_");
+ i += len;
+ }
+ if (sxe2_test_bit(SXE2_FLOW_HDR_UDP, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "UDP_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_TCP, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "TCP_");
+ i += len;
+ } else if (sxe2_test_bit(SXE2_FLOW_HDR_SCTP, flow->pattern_inner.hdrs)) {
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name) - i,
+ "SCTP_");
+ i += len;
+ }
+
+ len = snprintf(flow_type_name + i, sizeof(flow_type_name), "PAY");
+ i += len;
+
+ for (i = 0; i < SXE2_FLOW_TYPE_MAX; i++) {
+ if (sxe2_flow_type_name[i] == NULL)
+ continue;
+ if (strcmp(flow_type_name, sxe2_flow_type_name[i]) == 0) {
+ flow->meta.flow_type = i;
+ ret = 0;
+ break;
+ }
+ }
+ if (ret != 0)
+ PMD_LOG_ERR(DRV,
+ "Unsupported flow type. %s is not supported.", flow_type_name);
+ return ret;
+}
+
+static int32_t sxe2_flow_is_expandable_item(const struct rte_flow_item *item)
+{
+ int32_t ret = -EINVAL;
+ switch (item->type) {
+ case RTE_FLOW_ITEM_TYPE_ETH:
+ case RTE_FLOW_ITEM_TYPE_VLAN:
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ case RTE_FLOW_ITEM_TYPE_SCTP:
+ case RTE_FLOW_ITEM_TYPE_VXLAN:
+ case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+ case RTE_FLOW_ITEM_TYPE_GRE:
+ case RTE_FLOW_ITEM_TYPE_NVGRE:
+ case RTE_FLOW_ITEM_TYPE_GENEVE:
+ case RTE_FLOW_ITEM_TYPE_GTPU:
+ case RTE_FLOW_ITEM_TYPE_VOID:
+ case RTE_FLOW_ITEM_TYPE_END:
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+static int32_t sxe2_flow_valid_next_expansion(enum sxe2_expansion *current,
+ const struct rte_flow_item *item,
+ enum sxe2_flow_tunnel_type *tunnel_type, BITMAP_TYPE *flow_type)
+{
+ int32_t ret = -EINVAL;
+ const struct rte_flow_item *next;
+ const enum sxe2_expansion *next_expansion = current;
+ const struct sxe2_flow_expand_node *node;
+ uint8_t len = 0;
+ char typelist[512] = {0};
+ char error[1024] = {0};
+ enum sxe2_flow_tunnel_type tunnel_type_now = SXE2_FLOW_TUNNEL_TYPE_NONE;
+ enum sxe2_flow_tunnel_type tunnel_type_next = SXE2_FLOW_TUNNEL_TYPE_NONE;
+ uint8_t is_tunnel_now = 0;
+ uint8_t is_tunnel_next = 0;
+
+ if (item->type != sxe2_support_expansion[*current].type) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ next = item;
+ do {
+ next++;
+ if (next->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+ break;
+ } while (1);
+
+ node = &sxe2_support_expansion[*current];
+ next_expansion = node->next;
+ while (*next_expansion != 0) {
+ len = strlen(typelist);
+ snprintf(typelist + len, sizeof(typelist) - len,
+ "%s|", sxe2_support_expansion[*next_expansion].name);
+ if (sxe2_support_expansion[*next_expansion].type == next->type) {
+ ret = 0;
+ break;
+ }
+ next_expansion++;
+ }
+ if (ret != 0) {
+ snprintf(error, sizeof(error),
+ "The next item of %s only can be one of [%s].",
+ sxe2_support_expansion[*current].name, typelist);
+ PMD_LOG_ERR(INIT, "Invalid pattern sequence. %s", error);
+ goto l_end;
+ }
+ tunnel_type_now = sxe2_support_expansion[*current].tunnel_type;
+ tunnel_type_next = sxe2_support_expansion[*next_expansion].tunnel_type;
+ is_tunnel_now = sxe2_support_expansion[*current].is_tunnel;
+ is_tunnel_next = sxe2_support_expansion[*next_expansion].is_tunnel;
+
+
+ if (!is_tunnel_now && is_tunnel_next) {
+ if (tunnel_type_next == SXE2_FLOW_TUNNEL_TYPE_PARENT)
+ *tunnel_type = tunnel_type_now;
+ else
+ *tunnel_type = tunnel_type_next;
+ }
+
+l_end:
+ sxe2_set_bit(*current, flow_type);
+ *current = *next_expansion;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_eth(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next,
+ bool is_inner)
+{
+ const struct rte_flow_item_eth *eth_spec;
+ const struct rte_flow_item_eth *eth_mask;
+ const struct rte_ether_addr *dst_addr_mask;
+ const struct rte_ether_addr *src_addr_mask;
+ const struct rte_ether_addr *dst_addr_spec;
+ const struct rte_ether_addr *src_addr_spec;
+ rte_be16_t type_mask;
+ rte_be16_t type_spec;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ uint16_t ether_type;
+ eth_spec = item->spec;
+ eth_mask = item->mask;
+
+ if (eth_spec == NULL && eth_mask == NULL)
+ goto l_end;
+
+ dst_addr_mask = ð_mask->hdr.dst_addr;
+ src_addr_mask = ð_mask->hdr.src_addr;
+ dst_addr_spec = ð_spec->hdr.dst_addr;
+ src_addr_spec = ð_spec->hdr.src_addr;
+ type_mask = eth_mask->hdr.ether_type;
+ type_spec = eth_spec->hdr.ether_type;
+
+ if (eth_mask->has_vlan) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported eth mask has_vlan.");
+ PMD_LOG_ERR(DRV, "Unsupported eth mask has_vlan");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (!rte_is_zero_ether_addr(dst_addr_mask)) {
+ if (!rte_is_broadcast_ether_addr(dst_addr_mask))
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, pattern->map_mask);
+
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_DA, pattern->map_spec);
+ rte_memcpy(pattern->item_spec.eth.dst_addr, dst_addr_spec,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(pattern->item_mask.eth.dst_addr, dst_addr_mask,
+ RTE_ETHER_ADDR_LEN);
+ }
+ if (!rte_is_zero_ether_addr(src_addr_mask)) {
+ if (!rte_is_broadcast_ether_addr(src_addr_mask))
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, pattern->map_mask);
+
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_SA, pattern->map_spec);
+ rte_memcpy(pattern->item_spec.eth.src_addr, src_addr_spec,
+ RTE_ETHER_ADDR_LEN);
+ rte_memcpy(pattern->item_mask.eth.src_addr, src_addr_mask,
+ RTE_ETHER_ADDR_LEN);
+ }
+ if (type_mask != 0) {
+ if (type_mask != UINT16_MAX) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported eth ether_type mask");
+ PMD_LOG_ERR(DRV, "unsupported eth ether_type mask[0x%x].",
+ type_mask);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported eth ether_type match with next item.");
+ PMD_LOG_ERR(DRV, "unsupported eth ether_type match with next item.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ ether_type = rte_be_to_cpu_16(type_spec);
+ if (ether_type == RTE_ETHER_TYPE_IPV4 ||
+ ether_type == RTE_ETHER_TYPE_IPV6) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Ether_type unsupported ipv4/ipv6(0x0800/0x86DD).");
+ PMD_LOG_ERR(DRV, "Ether_type unsupported ipv4/ipv6(0x0800/0x86DD).");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (ether_type == RTE_ETHER_TYPE_VLAN || ether_type == RTE_ETHER_TYPE_QINQ ||
+ ether_type == RTE_ETHER_TYPE_QINQ1) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Ether_type unsupported vlan(0x8100/0x88a8/0x9100).");
+ PMD_LOG_ERR(DRV, "Ether_type unsupported vlan(0x8100/0x88a8/0x9100).");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (ether_type <= SXE2_FLOW_ETH_TYPE_MIN) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Ether_type need max 1500.");
+ PMD_LOG_ERR(DRV, "Ether_type need max 1500.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_ETH_TYPE, pattern->map_spec);
+ pattern->item_spec.eth.ether_type = type_spec;
+ pattern->item_mask.eth.ether_type = type_mask;
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_ETH, pattern->hdrs);
+ pattern->rss_type_allow |= RTE_ETH_RSS_ETH;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L2_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L2_SRC_ONLY;
+ if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END)
+ pattern->rss_type_allow |= RTE_ETH_RSS_L2_PAYLOAD;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vlan(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_vlan *vlan_spec;
+ const struct rte_flow_item_vlan *vlan_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ rte_be16_t vlan_tci_mask;
+ rte_be16_t vlan_tci_spec;
+ rte_be16_t eth_proto_mask;
+ rte_be16_t eth_proto_spec;
+ int32_t ret = 0;
+ vlan_spec = item->spec;
+ vlan_mask = item->mask;
+ bool is_qinq = false;
+
+ if (sxe2_test_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs))
+ is_qinq = true;
+
+ if (vlan_spec == NULL && vlan_mask == NULL)
+ goto l_end;
+
+ vlan_tci_mask = vlan_mask->hdr.vlan_tci;
+ vlan_tci_spec = vlan_spec->hdr.vlan_tci;
+ eth_proto_mask = vlan_mask->hdr.eth_proto;
+ eth_proto_spec = vlan_spec->hdr.eth_proto;
+
+ if (vlan_mask->has_more_vlan || vlan_mask->reserved) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported vlan mask has_qinq.");
+ PMD_LOG_ERR(DRV, "Unsupported vlan mask has_qinq");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (vlan_tci_mask) {
+ if (vlan_tci_spec == 0) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "vlan id can't be 0.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+ if (eth_proto_mask) {
+ if (eth_proto_mask != UINT16_MAX) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported vlan ether_type mask");
+ PMD_LOG_ERR(DRV, "unsupported vlan ether_type mask.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (eth_proto_spec != RTE_BE16(0x8100) &&
+ eth_proto_spec != RTE_BE16(0x88a8) &&
+ eth_proto_spec != RTE_BE16(0x9100)) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported vlan ether_type, only support 0x8100, 0x88a8 and 0x9100.");
+ PMD_LOG_ERR(DRV, "Unsupported vlan ether_type, only support 0x8100, 0x88a8 and 0x9100.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ if (!is_qinq) {
+ if (vlan_tci_mask) {
+ if (vlan_tci_mask == RTE_BE16(0x0fff)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_VID, pattern->map_spec);
+ } else if (vlan_tci_mask == UINT16_MAX) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_spec);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TCI, pattern->map_spec);
+ }
+ }
+ if (eth_proto_mask)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_S_TPID, pattern->map_spec);
+ } else {
+ if (vlan_tci_mask) {
+ if (vlan_tci_mask == RTE_BE16(0x0fff)) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_VID, pattern->map_spec);
+ } else if (vlan_tci_mask == UINT16_MAX) {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_spec);
+ } else {
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TCI, pattern->map_spec);
+ }
+ }
+ if (eth_proto_mask)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_C_TPID, pattern->map_spec);
+ }
+ if (is_qinq) {
+ pattern->item_spec.qinq.type = eth_proto_spec;
+ pattern->item_mask.qinq.type = eth_proto_mask;
+ pattern->item_spec.qinq.vlan = vlan_tci_spec;
+ pattern->item_mask.qinq.vlan = vlan_tci_mask;
+ } else {
+ pattern->item_spec.vlan.type = eth_proto_spec;
+ pattern->item_mask.vlan.type = eth_proto_mask;
+ pattern->item_spec.vlan.vlan = vlan_tci_spec;
+ pattern->item_mask.vlan.vlan = vlan_tci_mask;
+ }
+l_end:
+ pattern->rss_type_allow |= RTE_ETH_RSS_S_VLAN;
+ pattern->rss_type_allow |= RTE_ETH_RSS_C_VLAN;
+ if (!is_qinq)
+ sxe2_set_bit(SXE2_FLOW_HDR_VLAN, pattern->hdrs);
+ else
+ sxe2_set_bit(SXE2_FLOW_HDR_QINQ, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv4(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next,
+ bool is_inner)
+{
+ const struct rte_flow_item_ipv4 *ipv4_spec;
+ const struct rte_flow_item_ipv4 *ipv4_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ ipv4_spec = item->spec;
+ ipv4_mask = item->mask;
+
+ if (ipv4_mask == NULL && ipv4_spec == NULL)
+ goto l_end;
+
+ if (ipv4_mask->hdr.version_ihl || ipv4_mask->hdr.total_length ||
+ ipv4_mask->hdr.hdr_checksum || ipv4_mask->hdr.packet_id) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some IPv4 mask.");
+ PMD_LOG_ERR(DRV, "Unsupported some IPv4 mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (ipv4_mask->hdr.src_addr) {
+ if (ipv4_mask->hdr.src_addr != UINT32_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_SA, pattern->map_spec);
+ pattern->item_spec.ipv4.saddr = ipv4_spec->hdr.src_addr;
+ pattern->item_mask.ipv4.saddr = ipv4_mask->hdr.src_addr;
+ }
+ if (ipv4_mask->hdr.dst_addr) {
+ if (ipv4_mask->hdr.dst_addr != UINT32_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_DA, pattern->map_spec);
+ pattern->item_spec.ipv4.daddr = ipv4_spec->hdr.dst_addr;
+ pattern->item_mask.ipv4.daddr = ipv4_mask->hdr.dst_addr;
+ }
+
+ if (ipv4_mask->hdr.next_proto_id) {
+ if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "IPv4 proto id must be the last partten.");
+ PMD_LOG_ERR(DRV, "IPv4 proto id must be the last partten.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (ipv4_mask->hdr.next_proto_id != UINT8_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_PROT, pattern->map_spec);
+ pattern->item_spec.ipv4.protocol = ipv4_spec->hdr.next_proto_id;
+ pattern->item_mask.ipv4.protocol = ipv4_mask->hdr.next_proto_id;
+ }
+ if (ipv4_mask->hdr.time_to_live) {
+ if (ipv4_mask->hdr.time_to_live != UINT8_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TTL, pattern->map_mask);
+ if (ipv4_spec->hdr.time_to_live == 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "ipv4 ttl must be not 0.");
+ PMD_LOG_ERR(DRV, "ipv4 ttl must be not 0.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TTL, pattern->map_spec);
+ pattern->item_spec.ipv4.ttl = ipv4_spec->hdr.time_to_live;
+ pattern->item_mask.ipv4.ttl = ipv4_mask->hdr.time_to_live;
+ }
+ if (ipv4_mask->hdr.type_of_service) {
+ if (ipv4_mask->hdr.type_of_service != UINT8_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TOS, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV4_TOS, pattern->map_spec);
+ pattern->item_spec.ipv4.tos = ipv4_spec->hdr.type_of_service;
+ pattern->item_mask.ipv4.tos = ipv4_mask->hdr.type_of_service;
+ }
+ if (ipv4_mask->hdr.fragment_offset) {
+ if (ipv4_spec->hdr.fragment_offset == rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG) &&
+ ipv4_mask->hdr.fragment_offset == rte_cpu_to_be_16(RTE_IPV4_HDR_MF_FLAG)) {
+ if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "IPv4 frag offset must be the last partten.");
+ PMD_LOG_ERR(DRV, "IPv4 frag offset must be the last partten.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, pattern->hdrs);
+ } else {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported ipv4 fragment_offset cfg.");
+ PMD_LOG_ERR(DRV, "Unsupported ipv4 fragment_offset cfg.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs);
+ pattern->rss_type_allow |= RTE_ETH_RSS_IPV4;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_SRC_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_IPV4_CHKSUM;
+ if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END) {
+ pattern->rss_type_allow |= RTE_ETH_RSS_FRAG_IPV4;
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_OTHER;
+ }
+
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv6(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_ipv6 *ipv6_spec;
+ const struct rte_flow_item_ipv6 *ipv6_mask;
+ uint32_t vtc_flow_mask;
+ uint32_t tc_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ ipv6_spec = item->spec;
+ ipv6_mask = item->mask;
+ uint8_t ipv6_addr_mask[16] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+ uint8_t ipv6_addr_empty[16] = { 0 };
+
+ if (ipv6_mask == NULL && ipv6_spec == NULL)
+ goto l_end;
+
+ if (ipv6_mask->hdr.payload_len || ipv6_mask->has_hop_ext ||
+ ipv6_mask->has_route_ext || ipv6_mask->has_frag_ext ||
+ ipv6_mask->has_auth_ext || ipv6_mask->has_esp_ext ||
+ ipv6_mask->has_dest_ext || ipv6_mask->has_mobil_ext ||
+ ipv6_mask->has_hip_ext || ipv6_mask->has_shim6_ext) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some IPv6 mask");
+ PMD_LOG_ERR(DRV, "Unsupported some IPv6 mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (memcmp(&ipv6_mask->hdr.src_addr, ipv6_addr_empty,
+ sizeof(ipv6_addr_empty)) != 0) {
+ if (memcmp(&ipv6_mask->hdr.src_addr, ipv6_addr_mask,
+ sizeof(ipv6_addr_mask)) != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_SA, pattern->map_spec);
+ rte_memcpy(&pattern->item_spec.ipv6.saddr, &ipv6_spec->hdr.src_addr,
+ sizeof(ipv6_spec->hdr.src_addr));
+ rte_memcpy(&pattern->item_mask.ipv6.saddr, &ipv6_mask->hdr.src_addr,
+ sizeof(ipv6_mask->hdr.src_addr));
+ }
+ if (memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_empty,
+ sizeof(ipv6_addr_empty)) != 0) {
+ if (memcmp(&ipv6_mask->hdr.dst_addr, ipv6_addr_mask,
+ sizeof(ipv6_addr_mask)) != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DA, pattern->map_spec);
+ rte_memcpy(&pattern->item_spec.ipv6.daddr, &ipv6_spec->hdr.dst_addr,
+ sizeof(ipv6_spec->hdr.dst_addr));
+ rte_memcpy(&pattern->item_mask.ipv6.daddr, &ipv6_mask->hdr.dst_addr,
+ sizeof(ipv6_mask->hdr.dst_addr));
+ }
+ if (ipv6_mask->hdr.vtc_flow) {
+ vtc_flow_mask = rte_be_to_cpu_32(ipv6_mask->hdr.vtc_flow);
+ tc_mask = vtc_flow_mask & (SXE2_IPV6_TC_MASK << SXE2_IPV6_TC_SHIFT);
+ if (tc_mask != vtc_flow_mask) {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "ipv6 vtc_flow only support TC mask.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (tc_mask != (SXE2_IPV6_TC_MASK << SXE2_IPV6_TC_SHIFT))
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DSCP, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_DSCP, pattern->map_spec);
+ pattern->item_spec.ipv6.pri_ver_flow = ipv6_spec->hdr.vtc_flow;
+ pattern->item_mask.ipv6.pri_ver_flow = ipv6_mask->hdr.vtc_flow;
+ }
+ if (ipv6_mask->hdr.proto) {
+ if (next != SXE2_EXPANSION_OUTER_END && next != SXE2_EXPANSION_END) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "IPv6 proto id must be the last partten.");
+ PMD_LOG_ERR(DRV, "IPv6 proto id must be the last partten.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (ipv6_mask->hdr.proto != UINT8_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_PROT, pattern->map_spec);
+ pattern->item_spec.ipv6.nexthdr = ipv6_spec->hdr.proto;
+ pattern->item_mask.ipv6.nexthdr = ipv6_mask->hdr.proto;
+ }
+ if (ipv6_mask->hdr.hop_limits) {
+ if (ipv6_mask->hdr.hop_limits != UINT8_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_TTL, pattern->map_mask);
+
+ if (ipv6_spec->hdr.hop_limits == 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "ipv6 hop must be not 0.");
+ PMD_LOG_ERR(DRV, "ipv6 hop must be not 0.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_IPV6_TTL, pattern->map_spec);
+ pattern->item_spec.ipv6.hop_limit = ipv6_spec->hdr.hop_limits;
+ pattern->item_mask.ipv6.hop_limit = ipv6_mask->hdr.hop_limits;
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs);
+ pattern->rss_type_allow |= RTE_ETH_RSS_IPV6;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_SRC_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE32;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE48;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L3_PRE64;
+ if (next == SXE2_EXPANSION_OUTER_END || next == SXE2_EXPANSION_END)
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_OTHER;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_ipv6_frag_ext(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_spec;
+ const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ ipv6_frag_spec = item->spec;
+ ipv6_frag_mask = item->mask;
+
+ if (ipv6_frag_mask == NULL && ipv6_frag_spec == NULL)
+ goto l_end;
+
+ if (ipv6_frag_mask->hdr.reserved || ipv6_frag_mask->hdr.frag_data ||
+ ipv6_frag_mask->hdr.id || ipv6_frag_mask->hdr.next_header) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some IPv6 frag ext mask");
+ PMD_LOG_ERR(DRV, "Unsupported some IPv6 frag ext mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_IPV_FRAG, pattern->hdrs);
+ pattern->rss_type_allow |= RTE_ETH_RSS_FRAG_IPV6;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_tcp(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_tcp *tcp_spec;
+ const struct rte_flow_item_tcp *tcp_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ tcp_spec = item->spec;
+ tcp_mask = item->mask;
+
+ if (tcp_mask == NULL && tcp_spec == NULL)
+ goto l_end;
+
+ if (tcp_mask->hdr.sent_seq || tcp_mask->hdr.recv_ack ||
+ tcp_mask->hdr.data_off || tcp_mask->hdr.tcp_flags ||
+ tcp_mask->hdr.rx_win || tcp_mask->hdr.cksum ||
+ tcp_mask->hdr.tcp_urp) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some TCP mask");
+ PMD_LOG_ERR(DRV, "Unsupported some TCP mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (tcp_mask->hdr.src_port) {
+ if (tcp_mask->hdr.src_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_SRC_PORT, pattern->map_spec);
+ pattern->item_spec.tcp.source = tcp_spec->hdr.src_port;
+ pattern->item_mask.tcp.source = tcp_mask->hdr.src_port;
+ }
+ if (tcp_mask->hdr.dst_port) {
+ if (tcp_mask->hdr.dst_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_TCP_DST_PORT, pattern->map_spec);
+ pattern->item_spec.tcp.dest = tcp_spec->hdr.dst_port;
+ pattern->item_mask.tcp.dest = tcp_mask->hdr.dst_port;
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_TCP, pattern->hdrs);
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_TCP;
+ else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_TCP;
+
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_udp(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_udp *udp_spec;
+ const struct rte_flow_item_udp *udp_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ udp_spec = item->spec;
+ udp_mask = item->mask;
+
+ if (udp_mask == NULL && udp_spec == NULL)
+ goto l_end;
+
+ if (udp_mask->hdr.dgram_len || udp_mask->hdr.dgram_cksum) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some UDP mask");
+ PMD_LOG_ERR(DRV, "Unsupported some UDP mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (udp_mask->hdr.src_port) {
+ if (udp_mask->hdr.src_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_SRC_PORT, pattern->map_spec);
+ pattern->item_spec.udp.source = udp_spec->hdr.src_port;
+ pattern->item_mask.udp.source = udp_mask->hdr.src_port;
+ }
+ if (udp_mask->hdr.dst_port) {
+ if (udp_mask->hdr.dst_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_UDP_DST_PORT, pattern->map_spec);
+ pattern->item_spec.udp.dest = udp_spec->hdr.dst_port;
+ pattern->item_mask.udp.dest = udp_mask->hdr.dst_port;
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_UDP, pattern->hdrs);
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_UDP;
+ else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_UDP;
+
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_sctp(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_sctp *sctp_spec;
+ const struct rte_flow_item_sctp *sctp_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ sctp_spec = item->spec;
+ sctp_mask = item->mask;
+
+ if (sctp_mask == NULL && sctp_spec == NULL)
+ goto l_end;
+
+ if (sctp_mask->hdr.cksum || sctp_mask->hdr.tag) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some SCTP mask");
+ PMD_LOG_ERR(DRV, "Unsupported some SCTP mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (sctp_mask->hdr.src_port) {
+ if (sctp_mask->hdr.src_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_SRC_PORT, pattern->map_spec);
+ pattern->item_spec.sctp.src_port = sctp_spec->hdr.src_port;
+ pattern->item_mask.sctp.src_port = sctp_mask->hdr.src_port;
+ }
+ if (sctp_mask->hdr.dst_port) {
+ if (sctp_mask->hdr.dst_port != UINT16_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_SCTP_DST_PORT, pattern->map_spec);
+ pattern->item_spec.sctp.dst_port = sctp_spec->hdr.dst_port;
+ pattern->item_mask.sctp.dst_port = sctp_mask->hdr.dst_port;
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_SCTP, pattern->hdrs);
+ if (sxe2_test_bit(SXE2_FLOW_HDR_IPV4, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV4_SCTP;
+ else if (sxe2_test_bit(SXE2_FLOW_HDR_IPV6, pattern->hdrs))
+ pattern->rss_type_allow |= RTE_ETH_RSS_NONFRAG_IPV6_SCTP;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_SRC_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_DST_ONLY;
+ pattern->rss_type_allow |= RTE_ETH_RSS_L4_CHKSUM;
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_geneve(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_geneve *geneve_spec;
+ const struct rte_flow_item_geneve *geneve_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ geneve_spec = item->spec;
+ geneve_mask = item->mask;
+
+ if (!(geneve_spec && geneve_mask))
+ goto l_end;
+
+ if (geneve_mask->protocol || geneve_mask->ver_opt_len_o_c_rsvd0 || geneve_mask->rsvd1) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some Geneve mask");
+ PMD_LOG_ERR(DRV, "Unsupported some Geneve mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (geneve_mask->vni[0] || geneve_mask->vni[1] || geneve_mask->vni[2]) {
+ if (strcmp((const char *)geneve_mask->vni, "\xFF\xFF\xFF") != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_GENEVE_VNI, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_GENEVE_VNI, pattern->map_spec);
+ pattern->item_spec.geneve.vni = (geneve_spec->vni[2] << 16) |
+ (geneve_spec->vni[1] << 8) | geneve_spec->vni[0];
+ pattern->item_mask.geneve.vni = (geneve_mask->vni[2] << 16) |
+ (geneve_mask->vni[1] << 8) | geneve_mask->vni[0];
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_GENEVE, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_gtpu(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_gtp *gtpu_spec;
+ const struct rte_flow_item_gtp *gtpu_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ gtpu_spec = item->spec;
+ gtpu_mask = item->mask;
+
+ if (gtpu_mask == NULL && gtpu_spec == NULL)
+ goto l_end;
+
+ if (gtpu_mask->v_pt_rsv_flags || gtpu_mask->msg_type || gtpu_mask->msg_len) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some GTPU mask");
+ PMD_LOG_ERR(DRV, "Unsupported some GTPU mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (gtpu_mask->teid) {
+ if (gtpu_mask->teid != UINT32_MAX)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_GTPU_TEID, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_GTPU_TEID, pattern->map_spec);
+ pattern->item_spec.gtpu.teid = gtpu_spec->teid;
+ pattern->item_mask.gtpu.teid = gtpu_mask->teid;
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_GTPU, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_gre(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_gre *gre_spec;
+ const struct rte_flow_item_gre *gre_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ gre_spec = item->spec;
+ gre_mask = item->mask;
+
+ if (gre_mask == NULL && gre_spec == NULL)
+ goto l_end;
+
+ if (gre_mask->c_rsvd0_ver || gre_mask->protocol) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some GRE mask");
+ PMD_LOG_ERR(DRV, "Unsupported some GRE mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_nvgre(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_nvgre *nvgre_spec;
+ const struct rte_flow_item_nvgre *nvgre_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ nvgre_spec = item->spec;
+ nvgre_mask = item->mask;
+
+ if (nvgre_mask == NULL && nvgre_spec == NULL)
+ goto l_end;
+
+ if (nvgre_mask->c_k_s_rsvd0_ver || nvgre_mask->protocol || nvgre_mask->flow_id) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some NVGRE mask");
+ PMD_LOG_ERR(DRV, "Unsupported some NVGRE mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (nvgre_mask->tni[0] || nvgre_mask->tni[1] || nvgre_mask->tni[2]) {
+ if (strcmp((const char *)nvgre_mask->tni, "\xFF\xFF\xFF") != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_NVGRE_TNI, pattern->map_mask);
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_NVGRE_TNI, pattern->map_spec);
+ pattern->item_spec.nvgre.tni =
+ (nvgre_spec->tni[2] << 16) |
+ (nvgre_spec->tni[1] << 8) |
+ (nvgre_spec->tni[0]);
+ pattern->item_mask.nvgre.tni =
+ (nvgre_mask->tni[2] << 16) |
+ (nvgre_mask->tni[1] << 8) |
+ (nvgre_mask->tni[0]);
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_GRE, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vxlan(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_vxlan *vxlan_spec;
+ const struct rte_flow_item_vxlan *vxlan_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ vxlan_spec = item->spec;
+ vxlan_mask = item->mask;
+
+ if (vxlan_mask == NULL && vxlan_spec == NULL)
+ goto l_end;
+
+ if (vxlan_mask->flags ||
+ vxlan_mask->rsvd1 ||
+ vxlan_mask->rsvd0[0] ||
+ vxlan_mask->rsvd0[1] ||
+ vxlan_mask->rsvd0[2]) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some VXLAN mask");
+ PMD_LOG_ERR(DRV, "Unsupported some VXLAN mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (vxlan_mask->vni[0] || vxlan_mask->vni[1] || vxlan_mask->vni[2]) {
+ if (strcmp((const char *)vxlan_mask->vni, "\xFF\xFF\xFF") != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_mask);
+
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_spec);
+ pattern->item_spec.vxlan.vni =
+ (vxlan_spec->vni[2] << 16) |
+ (vxlan_spec->vni[1] << 8) |
+ (vxlan_spec->vni[0]);
+ pattern->item_mask.vxlan.vni =
+ (vxlan_mask->vni[2] << 16) |
+ (vxlan_mask->vni[1] << 8) |
+ (vxlan_mask->vni[0]);
+ }
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_VXLAN, pattern->hdrs);
+ return ret;
+}
+
+static int32_t sxe2_flow_parse_pattern_vxlan_gpe(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next __rte_unused,
+ bool is_inner)
+{
+ const struct rte_flow_item_vxlan_gpe *vxlan_gpe_spec;
+ const struct rte_flow_item_vxlan_gpe *vxlan_gpe_mask;
+ struct sxe2_flow_pattern *pattern = is_inner ? &flow->pattern_inner : &flow->pattern_outer;
+ int32_t ret = 0;
+ vxlan_gpe_spec = item->spec;
+ vxlan_gpe_mask = item->mask;
+
+ if (vxlan_gpe_mask == NULL && vxlan_gpe_spec == NULL)
+ goto l_end;
+
+ if (vxlan_gpe_mask->flags ||
+ vxlan_gpe_mask->protocol ||
+ vxlan_gpe_mask->rsvd1 ||
+ vxlan_gpe_mask->rsvd0[0] ||
+ vxlan_gpe_mask->rsvd0[1]) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ item, "Unsupported some VXLAN-GPE mask");
+ PMD_LOG_ERR(DRV, "Unsupported some VXLAN-GPE mask");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ if (vxlan_gpe_mask->vni[0] || vxlan_gpe_mask->vni[1] || vxlan_gpe_mask->vni[2]) {
+ if (strcmp((const char *)vxlan_gpe_mask->vni, "\xFF\xFF\xFF") != 0)
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_mask);
+
+ sxe2_set_bit(SXE2_FLOW_FLD_ID_VXLAN_VNI, pattern->map_spec);
+ pattern->item_spec.vxlan.vni =
+ (vxlan_gpe_spec->vni[2] << 16) |
+ (vxlan_gpe_spec->vni[1] << 8) |
+ (vxlan_gpe_spec->vni[0]);
+ pattern->item_mask.vxlan.vni =
+ (vxlan_gpe_mask->vni[2] << 16) |
+ (vxlan_gpe_mask->vni[1] << 8) |
+ (vxlan_gpe_mask->vni[0]);
+ }
+
+l_end:
+ sxe2_set_bit(SXE2_FLOW_HDR_VXLAN, pattern->hdrs);
+ return ret;
+}
+
+struct sxe2_flow_parse_pattern_ops sxe2_flow_parse_pattern_list[] = {
+ [SXE2_EXPANSION_OUTER_ETH] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_eth,
+ },
+ [SXE2_EXPANSION_OUTER_VLAN] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_vlan,
+ },
+ [SXE2_EXPANSION_OUTER_QINQ] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_vlan,
+ },
+ [SXE2_EXPANSION_OUTER_IPV4] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_ipv4,
+ },
+ [SXE2_EXPANSION_OUTER_IPV6] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_ipv6,
+ },
+ [SXE2_EXPANSION_OUTER_IPV6_FRAG_EXT] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_ipv6_frag_ext,
+ },
+ [SXE2_EXPANSION_OUTER_TCP] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_tcp,
+ },
+ [SXE2_EXPANSION_OUTER_UDP] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_udp,
+ },
+ [SXE2_EXPANSION_OUTER_SCTP] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_sctp,
+ },
+ [SXE2_EXPANSION_GENEVE] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_geneve,
+ },
+ [SXE2_EXPANSION_GTPU] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_gtpu,
+ },
+ [SXE2_EXPANSION_GRE] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_gre,
+ },
+ [SXE2_EXPANSION_NVGRE] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_nvgre,
+ },
+ [SXE2_EXPANSION_VXLAN] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_vxlan,
+ },
+ [SXE2_EXPANSION_VXLAN_GPE] = {
+ .is_inner = false,
+ .func = sxe2_flow_parse_pattern_vxlan_gpe,
+ },
+ [SXE2_EXPANSION_ETH] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_eth,
+ },
+ [SXE2_EXPANSION_VLAN] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_vlan,
+ },
+ [SXE2_EXPANSION_IPV4] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_ipv4,
+ },
+ [SXE2_EXPANSION_IPV6] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_ipv6,
+ },
+ [SXE2_EXPANSION_IPV6_FRAG_EXT] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_ipv6_frag_ext,
+ },
+ [SXE2_EXPANSION_TCP] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_tcp,
+ },
+ [SXE2_EXPANSION_UDP] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_udp,
+ },
+ [SXE2_EXPANSION_SCTP] = {
+ .is_inner = true,
+ .func = sxe2_flow_parse_pattern_sctp,
+ },
+
+};
+
+int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev __rte_unused,
+ const struct rte_flow_item patterns[],
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow)
+{
+ int32_t ret = 0;
+ const struct rte_flow_item *item = patterns;
+ enum sxe2_expansion now = SXE2_EXPANSION_OUTER_ETH;
+ enum sxe2_expansion next = SXE2_EXPANSION_OUTER_ETH;
+ enum sxe2_flow_tunnel_type tunnel_type = SXE2_FLOW_TUNNEL_TYPE_NONE;
+ DECLARE_BITMAP(flow_type, SXE2_EXPANSION_MAX);
+ sxe2_bitmap_zero(flow_type, SXE2_EXPANSION_MAX);
+ sxe2_flow_parse_pattern_func_t func;
+ bool is_inner = false;
+
+ for (item = patterns; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+ if (item->type == RTE_FLOW_ITEM_TYPE_VOID)
+ continue;
+
+ if (item->last) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "FANV not support range pattern.");
+ PMD_LOG_ERR(DRV, "flow not supported range pattern.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ ret = sxe2_flow_is_expandable_item(item);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Unsupported item type.");
+ PMD_LOG_ERR(DRV, "Unsupported item type: %d", item->type);
+ goto l_end;
+ }
+ next = now;
+ ret = sxe2_flow_valid_next_expansion(&next, item,
+ &tunnel_type, flow_type);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Invalid pattern sequence for rule.");
+ PMD_LOG_ERR(DRV, "Invalid pattern sequence for rule.");
+ goto l_end;
+ }
+
+ if ((item->spec != NULL && item->mask == NULL) ||
+ (item->spec == NULL && item->mask != NULL)) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM, item,
+ "Invalid pattern spec miss macth mask for rule.");
+ PMD_LOG_ERR(DRV, "Invalid pattern spec miss macth mask for rule.");
+ goto l_end;
+ }
+
+ func = sxe2_flow_parse_pattern_list[now].func;
+ is_inner = sxe2_flow_parse_pattern_list[now].is_inner;
+ ret = func(item, error, flow, next, is_inner);
+ if (ret != 0)
+ goto l_end;
+ now = next;
+ }
+ if (sxe2_bitmap_weight(flow->pattern_outer.hdrs, SXE2_FLOW_HDR_MAX) > 0)
+ flow->has_hdr = 1;
+
+ if (sxe2_bitmap_weight(flow->pattern_inner.map_mask, SXE2_FLOW_FLD_ID_MAX) > 0 ||
+ sxe2_bitmap_weight(flow->pattern_outer.map_mask, SXE2_FLOW_FLD_ID_MAX) > 0)
+ flow->has_mask = 1;
+
+ if (sxe2_bitmap_weight(flow->pattern_inner.map_spec, SXE2_FLOW_FLD_ID_MAX) > 0 ||
+ sxe2_bitmap_weight(flow->pattern_outer.map_spec, SXE2_FLOW_FLD_ID_MAX) > 0)
+ flow->has_spec = 1;
+
+ flow->meta.tunnel_type = tunnel_type;
+ if (flow->has_hdr) {
+ ret = sxe2_flow_get_flow_type(flow);
+ if (ret != 0) {
+ rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ITEM,
+ NULL, "Unsupported flow type.");
+ goto l_end;
+ }
+ }
+ sxe2_bitmap_copy(flow->flow_type, flow_type, SXE2_EXPANSION_MAX);
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_flow_parse_pattern.h b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
new file mode 100644
index 0000000000..69d83a6ea6
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_flow_parse_pattern.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef SXE2_FLOW_PARSE_PATTERN_H_
+#define SXE2_FLOW_PARSE_PATTERN_H_
+#include <rte_flow_driver.h>
+#include "sxe2_osal.h"
+#include "sxe2_flow_define.h"
+
+#define SXE2_FLOW_EXPAND_NEXT(...) \
+ ((const enum sxe2_expansion []){ \
+ __VA_ARGS__, 0, \
+ })
+
+struct sxe2_flow_expand_node {
+ const enum rte_flow_item_type type;
+ const enum sxe2_flow_tunnel_type tunnel_type;
+ const uint8_t is_tunnel;
+ const enum sxe2_expansion *const next;
+ const char *const name;
+};
+
+typedef int32_t (*sxe2_flow_parse_pattern_func_t)(const struct rte_flow_item *item,
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow,
+ enum sxe2_expansion next,
+ bool is_inner);
+
+struct sxe2_flow_parse_pattern_ops {
+ bool is_inner;
+ sxe2_flow_parse_pattern_func_t func;
+};
+
+int32_t sxe2_flow_parse_pattern(struct rte_eth_dev *dev,
+ const struct rte_flow_item patterns[],
+ struct rte_flow_error *error,
+ struct sxe2_flow *flow);
+
+#endif /* SXE2_FLOW_PARSE_PATTERN_H_ */
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
index fd9cd4b1ff..c26098ef3a 100644
--- a/drivers/net/sxe2/sxe2_irq.c
+++ b/drivers/net/sxe2/sxe2_irq.c
@@ -20,6 +20,7 @@
#include "sxe2vf_regs.h"
#include "sxe2_host_regs.h"
#include "sxe2_cmd_chnl.h"
+#include "sxe2_switchdev.h"
#define SXE2_INT_EVENT_OICR_ALL (SXE2_PF_INT_OICR_SWINT | \
SXE2_PF_INT_OICR_LAN_TX_ERR | \
@@ -59,6 +60,14 @@ static void sxe2_event_irq_common_handler(struct sxe2_adapter *adapter, uint64_t
RTE_ETH_EVENT_INTR_LSC,
NULL);
}
+ if (oicr & RTE_BIT32(SXE2_COM_SW_MODE_SWITCHDEV)) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "event notify switchdev");
+ (void)sxe2_switchdev_notify_callback(adapter, true);
+ }
+ if (oicr & RTE_BIT32(SXE2_COM_SW_MODE_LEGACY)) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "event notify legacy");
+ (void)sxe2_switchdev_notify_callback(adapter, false);
+ }
}
static uint32_t sxe2_event_intr_handle(void *param __rte_unused)
@@ -882,6 +891,42 @@ int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev)
return ret;
}
+int32_t sxe2_repr_rxq_intr_enable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ uint16_t rxq_cnt = dev->data->nb_rx_queues;
+ int32_t ret = 0;
+ uint16_t qid = adapter->repr_priv_data->repr_q_id;
+ uint32_t val;
+
+ if (!rxq_cnt)
+ goto l_end;
+
+ sxe2_pci_hw_irq_disable(adapter, qid);
+ sxe2_pci_hw_int_itr_set(adapter, qid, SXE2_ITR_INTERVAL_NORMAL);
+ ret = sxe2_drv_rxq_bind_irq(adapter, qid, qid);
+ if (ret != 0) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "RXQ[%u] bind IRQ[%u] failed.",
+ qid, qid);
+ goto l_end;
+ }
+ sxe2_pci_hw_irq_enable(adapter, qid);
+
+ val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+ if ((val & SXE2VF_DYN_CTL_INTENABLE) == 0)
+ goto l_end;
+
+ sxe2_pci_hw_msix_disable(adapter, qid);
+ sxe2_pci_hw_irq_trigger(adapter, qid);
+ val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+ sxe2_pci_hw_irq_clear_pba(adapter, qid);
+ val = sxe2_pci_hw_irq_dyn_ctl_read(adapter, qid);
+ sxe2_pci_hw_msix_enable(adapter, qid);
+
+l_end:
+ return ret;
+}
+
void sxe2_rxq_intr_disable(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter =
@@ -902,6 +947,15 @@ void sxe2_rxq_intr_disable(struct rte_eth_dev *dev)
return;
}
+void sxe2_repr_rxq_intr_disable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ uint16_t qid = adapter->repr_priv_data->repr_q_id;
+
+ sxe2_pci_hw_irq_disable(adapter, qid);
+ (void)sxe2_drv_rxq_unbind_irq(adapter, qid);
+}
+
int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
{
struct sxe2_adapter *adapter =
diff --git a/drivers/net/sxe2/sxe2_irq.h b/drivers/net/sxe2/sxe2_irq.h
index 31216240e6..b56c2664b8 100644
--- a/drivers/net/sxe2/sxe2_irq.h
+++ b/drivers/net/sxe2/sxe2_irq.h
@@ -60,8 +60,12 @@ void sxe2_sw_irq_ctx_hw_cap_set(struct sxe2_adapter *adapter,
int32_t sxe2_rxq_intr_enable(struct rte_eth_dev *dev);
+int32_t sxe2_repr_rxq_intr_enable(struct rte_eth_dev *dev);
+
void sxe2_rxq_intr_disable(struct rte_eth_dev *dev);
+void sxe2_repr_rxq_intr_disable(struct rte_eth_dev *dev);
+
int32_t sxe2_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id);
int32_t sxe2_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id);
diff --git a/drivers/net/sxe2/sxe2_queue.c b/drivers/net/sxe2/sxe2_queue.c
index 220cab6fce..afb2681b72 100644
--- a/drivers/net/sxe2/sxe2_queue.c
+++ b/drivers/net/sxe2/sxe2_queue.c
@@ -24,7 +24,11 @@ int32_t sxe2_queues_init(struct rte_eth_dev *dev)
struct sxe2_rx_queue *rxq;
uint16_t nb_rxq;
- frame_size = dev->data->mtu + SXE2_ETH_OVERHEAD;
+ if (adapter->is_dev_repr)
+ frame_size = SXE2_FRAME_SIZE_MAX - SXE2_ETH_OVERHEAD;
+ else
+ frame_size = dev->data->mtu + SXE2_ETH_OVERHEAD;
+
for (nb_rxq = 0; nb_rxq < dev->data->nb_rx_queues; nb_rxq++) {
rxq = dev->data->rx_queues[nb_rxq];
if (!rxq)
diff --git a/drivers/net/sxe2/sxe2_stats.c b/drivers/net/sxe2/sxe2_stats.c
index 7ea2815fa3..2f8bb432c4 100644
--- a/drivers/net/sxe2/sxe2_stats.c
+++ b/drivers/net/sxe2/sxe2_stats.c
@@ -154,7 +154,12 @@ static int32_t sxe2_vsi_hw_stats_get_update(struct sxe2_adapter *adapter)
ret = sxe2_drv_get_vsi_stats(adapter);
if (ret) {
- PMD_LOG_ERR(DRV, "get vsi stats failed, ret:%d.", ret);
+ if (adapter->is_dev_repr) {
+ PMD_LOG_WARN(DRV, "get repr vsi stats failed, ret:%d.", ret);
+ ret = 0;
+ } else {
+ PMD_LOG_ERR(DRV, "get vsi stats failed, ret:%d.", ret);
+ }
goto l_end;
}
@@ -231,7 +236,7 @@ static void sxe2_stats_update(struct sxe2_adapter *adapter)
stats->rx_sw_drop_bytes = sw_stats->rx_sw_drop_bytes +
sw_stats_prev->rx_sw_drop_bytes;
- if (adapter->dev_type != SXE2_DEV_T_VF) {
+ if (adapter->dev_type != SXE2_DEV_T_VF && !adapter->is_dev_repr) {
stats->rx_out_of_buffer = hw_stats->rx_out_of_buffer;
stats->rx_qblock_drop = hw_stats->rx_qblock_drop;
stats->tx_frame_good = hw_stats->tx_frame_good;
@@ -364,7 +369,7 @@ int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
if (rte_eal_process_type() == RTE_PROC_SECONDARY)
return sxe2_mp_req_get_xstats(dev, xstats, usr_cnt);
- if (adapter->dev_type == SXE2_DEV_T_VF)
+ if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr)
xstats_cnt = SXE2_XSTAT_CNT_VF;
else
xstats_cnt = SXE2_XSTAT_CNT_PF;
@@ -387,7 +392,7 @@ int32_t sxe2_xstats_info_get(struct rte_eth_dev *dev,
goto end;
}
- if (adapter->dev_type == SXE2_DEV_T_VF) {
+ if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr) {
sxe2_stats_update(adapter);
for (i = 0; i < xstats_cnt; i++) {
(void)sxe2_xstat_vf_offset_get(i, &offset);
@@ -431,7 +436,7 @@ int32_t sxe2_xstats_names_get(__rte_unused struct rte_eth_dev *dev,
int32_t ret = -1;
uint32_t xstats_cnt = 0;
- if (adapter->dev_type == SXE2_DEV_T_VF) {
+ if (adapter->dev_type == SXE2_DEV_T_VF || adapter->is_dev_repr) {
field = sxe2_xstats_field_vf;
xstats_cnt = SXE2_XSTAT_CNT_VF;
} else {
@@ -476,7 +481,7 @@ int32_t sxe2_stats_hw_reset(struct rte_eth_dev *dev)
PMD_LOG_ERR(DRV, "reset vsi stats failed, ret:%d.", ret);
goto l_end;
}
- if (adapter->dev_type != SXE2_DEV_T_VF) {
+ if (adapter->dev_type != SXE2_DEV_T_VF && !adapter->is_dev_repr) {
ret = sxe2_drv_mac_stats_reset(adapter);
if (ret) {
PMD_LOG_ERR(DRV, "reset mac stats failed, ret:%d.", ret);
diff --git a/drivers/net/sxe2/sxe2_switchdev.c b/drivers/net/sxe2/sxe2_switchdev.c
new file mode 100644
index 0000000000..44703cfb5c
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_switchdev.c
@@ -0,0 +1,332 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_os.h>
+#include <rte_tailq.h>
+#include "sxe2_osal.h"
+#include "sxe2_mac.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_switchdev.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_host_regs.h"
+
+int32_t sxe2_uplink_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+ goto l_end;
+ }
+
+ ret = sxe2_drv_switchdev_uplink_config(adapter, false);
+l_end:
+ return ret;
+}
+
+int32_t sxe2_uplink_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+ goto l_end;
+ }
+
+ ret = sxe2_drv_switchdev_uplink_config(adapter, true);
+l_end:
+ return ret;
+}
+
+int32_t sxe2_repr_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ uint16_t repr_id = 0;
+ struct rte_eth_dev *repr_dev;
+ struct sxe2_adapter *repr_adapter;
+ struct sxe2_switchdev_repr_info repr_vf;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+ goto l_end;
+ }
+
+ for (repr_id = 0; repr_id < adapter->repr_ctxt.nb_repr_vf; repr_id++) {
+ repr_dev = adapter->repr_ctxt.vf_rep_eth_dev[repr_id];
+ if (!repr_dev)
+ continue;
+ repr_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(repr_dev);
+ if (repr_adapter &&
+ repr_adapter->repr_priv_data &&
+ repr_adapter->repr_priv_data->cp_vsi) {
+ memset(&repr_vf, 0, sizeof(struct sxe2_switchdev_repr_info));
+
+ repr_vf.repr_pf_id = repr_adapter->repr_priv_data->repr_pf_id;
+ repr_vf.repr_vf_id = repr_adapter->repr_priv_data->repr_vf_id;
+ repr_vf.cp_vsi_id = repr_adapter->repr_priv_data->cp_vsi->vsi_id;
+ repr_vf.repr_q_id = repr_adapter->repr_priv_data->repr_q_id;
+ ret = sxe2_drv_switchdev_repr_vf_config(adapter, &repr_vf,
+ false);
+ }
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_repr_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ uint16_t repr_id = 0;
+ struct rte_eth_dev *repr_dev;
+ struct sxe2_adapter *repr_adapter;
+ struct sxe2_switchdev_repr_info repr_vf;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+ goto l_end;
+ }
+
+ for (repr_id = 0; repr_id < adapter->repr_ctxt.nb_repr_vf; repr_id++) {
+ repr_dev = adapter->repr_ctxt.vf_rep_eth_dev[repr_id];
+ if (!repr_dev)
+ continue;
+ repr_adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(repr_dev);
+ if (repr_adapter &&
+ repr_adapter->repr_priv_data &&
+ repr_adapter->repr_priv_data->cp_vsi) {
+ memset(&repr_vf, 0, sizeof(struct sxe2_switchdev_repr_info));
+
+ repr_vf.repr_pf_id = repr_adapter->repr_priv_data->repr_pf_id;
+ repr_vf.repr_vf_id = repr_adapter->repr_priv_data->repr_vf_id;
+ repr_vf.cp_vsi_id = repr_adapter->repr_priv_data->cp_vsi->vsi_id;
+ repr_vf.repr_q_id = repr_adapter->repr_priv_data->repr_q_id;
+ ret = sxe2_drv_switchdev_repr_vf_config(adapter, &repr_vf, true);
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+void sxe2_free_repr_info(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (adapter->repr_ctxt.vf_rep_eth_dev) {
+ rte_free(adapter->repr_ctxt.vf_rep_eth_dev);
+ adapter->repr_ctxt.vf_rep_eth_dev = NULL;
+ }
+
+ adapter->repr_ctxt.nb_repr_vf = 0;
+}
+
+static int32_t sxe2_switchdev_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode is not switchdev");
+ goto l_end;
+ }
+
+ adapter->switchdev_info.is_switchdev = false;
+
+ if (!adapter->flow_isolate_cfg && adapter->flow_isolated)
+ adapter->flow_isolated = false;
+
+ ret = sxe2_l2_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+ ret = sxe2_switchdev_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_switchdev_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "Current mode switch dev");
+ goto l_end;
+ }
+
+ adapter->switchdev_info.is_switchdev = true;
+
+ if (adapter->flow_isolate_cfg && !adapter->flow_isolated)
+ adapter->flow_isolated = true;
+
+ ret = sxe2_l2_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+ ret = sxe2_switchdev_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update switchdev rule");
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_switchdev_notify_callback(struct sxe2_adapter *adapter, bool set)
+{
+ struct rte_eth_dev *dev = &rte_eth_devices[adapter->dev_info.dev_data->port_id];
+ int32_t ret = 0;
+ bool cur_switchdev_set = false;
+
+ if (adapter->repr_ctxt.nb_repr_vf) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "switch dev notify remove dev");
+ rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RMV, NULL);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_switchdev_mode_get(adapter, &cur_switchdev_set);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get switchdev mode");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (set != cur_switchdev_set) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "current switchdev mode miss macth");
+ goto l_end;
+ }
+
+ if (set) {
+ ret = sxe2_switchdev_set(adapter);
+ if (ret != 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set switchdev");
+ goto l_end;
+ }
+ } else {
+ ret = sxe2_switchdev_clear(adapter);
+ if (ret != 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear switchdev");
+ goto l_end;
+ }
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_switchdev_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ PMD_DEV_LOG_INFO(adapter, INIT, "switchdev init");
+
+ if (adapter->switchdev_info.is_switchdev)
+ adapter->flow_isolated = true;
+
+ adapter->repr_priv_data = NULL;
+ adapter->repr_ctxt.nb_repr_vf = 0;
+
+ return 0;
+}
+
+int32_t sxe2_switchdev_uninit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ PMD_DEV_LOG_INFO(adapter, INIT, "switchdev uinit");
+
+ if (adapter->repr_priv_data) {
+ rte_free(adapter->repr_priv_data);
+ adapter->repr_priv_data = NULL;
+ }
+
+ return 0;
+}
+
+int32_t sxe2_switchdev_dev_info_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_dev_info *dev_info = &adapter->dev_info;
+ struct sxe2_dev_info *parent_dev_info = &parent_adapter->dev_info;
+ struct sxe2_drv_dev_info_resp dev_info_resp = {0};
+ struct sxe2_drv_dev_fw_info_resp dev_fw_info_resp = {0};
+ int32_t ret = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ dev_info->pci = parent_dev_info->pci;
+ dev_info->pci.max_vfs = 0;
+
+ ret = sxe2_drv_dev_info_get(adapter, &dev_info_resp);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_dev_fw_info_get(adapter, &dev_fw_info_resp);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get device fw info, ret=[%d]", ret);
+ goto l_end;
+ }
+ dev_info->fw.build_id = dev_fw_info_resp.build_id;
+ dev_info->fw.fix_version_id = dev_fw_info_resp.fix_version_id;
+ dev_info->fw.sub_version_id = dev_fw_info_resp.sub_version_id;
+ dev_info->fw.main_version_id = dev_fw_info_resp.main_version_id;
+
+ rte_ether_addr_copy((struct rte_ether_addr *)dev_info_resp.mac_addr,
+ (struct rte_ether_addr *)dev_info->mac.perm_addr);
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_switchdev_repr_private_data_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter, uint16_t repr_id)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_repr_private_data *repr_priv_data = adapter->repr_priv_data;
+ int32_t ret = 0;
+
+ if (repr_priv_data != NULL)
+ goto l_end;
+
+ repr_priv_data = rte_zmalloc("sxe2_repr_priv_data",
+ sizeof(struct sxe2_repr_private_data), 0);
+ if (repr_priv_data == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to malloc representor private data.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ repr_priv_data->parent_adapter = parent_adapter;
+ repr_priv_data->repr_id = repr_id;
+ repr_priv_data->cp_vsi =
+ TAILQ_FIRST(&parent_adapter->vsi_ctxt.other_vsi_list);
+ if (repr_priv_data->cp_vsi == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to get cp vsi.");
+ ret = -EINVAL;
+ goto l_free;
+ }
+ repr_priv_data->repr_q_id = repr_id;
+ repr_priv_data->repr_pf_id = parent_adapter->pf_idx;
+ repr_priv_data->repr_vf_id = repr_id;
+ repr_priv_data->repr_vf_k_vsi_id =
+ parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id;
+ repr_priv_data->repr_vf_u_vsi_id =
+ parent_adapter->repr_ctxt.repr_vf_id[repr_id].dpdk_vsi_id;
+
+ repr_priv_data->repr_vf_vsi_id =
+ parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id !=
+ SXE2_INVALID_VSI_ID ?
+ parent_adapter->repr_ctxt.repr_vf_id[repr_id].kernel_vsi_id :
+ parent_adapter->repr_ctxt.repr_vf_id[repr_id].dpdk_vsi_id;
+
+ adapter->repr_priv_data = repr_priv_data;
+ goto l_end;
+l_free:
+ rte_free(repr_priv_data);
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_switchdev.h b/drivers/net/sxe2/sxe2_switchdev.h
new file mode 100644
index 0000000000..0a74454424
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_switchdev.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_SWITCHDEV_H__
+#define __SXE2_SWITCHDEV_H__
+#include <ethdev_driver.h>
+
+struct sxe2_adapter;
+
+int32_t sxe2_uplink_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_uplink_set(struct sxe2_adapter *adapter);
+
+int32_t sxe2_repr_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_repr_set(struct sxe2_adapter *adapter);
+
+int32_t sxe2_switchdev_notify_callback(struct sxe2_adapter *adapter, bool set);
+
+int32_t sxe2_switchdev_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_switchdev_uninit(struct rte_eth_dev *dev);
+
+void sxe2_free_repr_info(struct rte_eth_dev *dev);
+
+int32_t sxe2_switchdev_dev_info_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter);
+
+int32_t sxe2_switchdev_repr_private_data_init(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter, uint16_t repr_id);
+
+#endif /* __SXE2_SWITCHDEV_H__ */
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index a919a84450..3861e31688 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -151,6 +151,13 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
uint32_t batch_flags = 0;
PMD_INIT_FUNC_TRACE();
+
+ if (adapter->is_dev_repr) {
+ dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+ dev->tx_pkt_burst = sxe2_tx_pkts;
+ tx_mode_flags = 0;
+ return;
+ }
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
tx_mode_flags = 0;
ret = sxe2_tx_vec_support_check(dev, &vec_flags);
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index 8b6e585c36..f3c4fa0d91 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -454,6 +454,14 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
desc_l2tag2 = tx_pkt->vlan_tci_outer;
desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_CMD_IL2TAG2_MASK;
}
+ if (unlikely(vsi->vsi_type == SXE2_VSI_T_DPDK_ESW)) {
+ desc_type_cmd_tso_mss |=
+ (SXE2_TX_CTXT_DESC_CMD_SWTCH_VSI <<
+ SXE2_TX_CTXT_DESC_CMD_SHIFT);
+ desc_type_cmd_tso_mss |=
+ ((vsi->adapter->repr_priv_data->repr_vf_vsi_id & 0x3FFULL)
+ << SXE2_TX_CTXT_DESC_VSI_SHIFT);
+ }
ctxt_desc->tunneling_params =
rte_cpu_to_le_32(desc_tunneling_params);
diff --git a/drivers/net/sxe2/sxe2_vsi.c b/drivers/net/sxe2/sxe2_vsi.c
index baaa20c02e..d29480b931 100644
--- a/drivers/net/sxe2/sxe2_vsi.c
+++ b/drivers/net/sxe2/sxe2_vsi.c
@@ -98,9 +98,15 @@ static struct sxe2_vsi *sxe2_vsi_node_create(struct sxe2_adapter *adapter,
static void sxe2_vsi_node_free(struct sxe2_vsi *vsi)
{
+ struct sxe2_adapter *adapter;
+
if (!vsi)
return;
+ adapter = vsi->adapter;
+ if (vsi->vsi_type == SXE2_VSI_T_ESW)
+ TAILQ_REMOVE(&adapter->vsi_ctxt.other_vsi_list, vsi, next);
+
rte_free(vsi);
vsi = NULL;
}
@@ -174,10 +180,54 @@ static int32_t sxe2_main_vsi_create(struct sxe2_adapter *adapter)
return ret;
}
+int32_t sxe2_other_vsi_create(struct sxe2_adapter *adapter, uint16_t cnt_vf)
+{
+ int32_t ret = 0;
+ struct sxe2_vsi *other_vsi = NULL;
+ uint16_t vsi_id = SXE2_INVALID_VSI_ID;
+
+ PMD_INIT_FUNC_TRACE();
+
+ other_vsi = sxe2_vsi_node_create(adapter, SXE2_INVALID_VSI_ID, SXE2_VSI_T_DPDK_ESW);
+ if (other_vsi == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ ret = sxe2_drv_switchdev_cpvsi_get(adapter, &vsi_id);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to query vsi from fw, ret=%d", ret);
+ goto l_free_vsi;
+ }
+
+ other_vsi->vsi_id = vsi_id;
+ other_vsi->vsi_type = SXE2_VSI_T_DPDK_ESW;
+
+ ret = sxe2_drv_vsi_info_get(adapter, other_vsi);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to query vsi info from fw, ret=%d", ret);
+ goto l_free_vsi;
+ }
+
+ other_vsi->txqs.q_cnt = RTE_MIN(cnt_vf, other_vsi->txqs.q_cnt);
+ other_vsi->rxqs.q_cnt = RTE_MIN(cnt_vf, other_vsi->rxqs.q_cnt);
+ other_vsi->irqs.avail_cnt = RTE_MIN(cnt_vf, other_vsi->irqs.avail_cnt);
+
+ TAILQ_INSERT_TAIL(&adapter->vsi_ctxt.other_vsi_list, other_vsi, next);
+ goto l_end;
+
+l_free_vsi:
+ sxe2_vsi_node_free(other_vsi);
+l_end:
+ return ret;
+}
+
int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
int32_t ret = 0;
+ uint16_t srcvsi_list[SXE2_SRCVSI_PRUNE_MAX_NUM];
+ uint16_t srcvsi_cnt;
PMD_INIT_FUNC_TRACE();
@@ -187,6 +237,18 @@ int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
goto l_end;
}
+ if (adapter->vsi_ctxt.kernel_vsi_id != SXE2_INVALID_VSI_ID) {
+ srcvsi_list[0] = adapter->vsi_ctxt.kernel_vsi_id;
+ srcvsi_list[1] = adapter->vsi_ctxt.dpdk_vsi_id;
+ srcvsi_cnt = 2;
+ ret = sxe2_drv_srcvsi_prune_config(adapter, srcvsi_list, srcvsi_cnt, true);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to set src vsi to fw, ret=%d", ret);
+ goto l_end;
+ }
+ PMD_LOG_DEBUG(DRV, "Successfully set src vsi");
+ }
+
l_end:
return ret;
}
@@ -194,21 +256,105 @@ int32_t sxe2_vsi_init(struct rte_eth_dev *dev)
void sxe2_vsi_uninit(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_vsi *var, *tvar;
int32_t ret;
+ uint16_t srcvsi_list[SXE2_SRCVSI_PRUNE_MAX_NUM];
+ uint16_t srcvsi_cnt;
if (adapter->vsi_ctxt.main_vsi == NULL) {
PMD_LOG_INFO(DRV, "vsi is not created, no need to destroy.");
goto l_end;
}
+ if (adapter->vsi_ctxt.kernel_vsi_id != SXE2_INVALID_VSI_ID) {
+ srcvsi_list[0] = adapter->vsi_ctxt.kernel_vsi_id;
+ srcvsi_list[1] = adapter->vsi_ctxt.dpdk_vsi_id;
+ srcvsi_cnt = 2;
+ ret = sxe2_drv_srcvsi_prune_config(adapter, srcvsi_list,
+ srcvsi_cnt, false);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to clear src vsi to fw, ret=%d", ret);
+ if (ret == -EPERM)
+ goto l_free;
+ goto l_end;
+ }
+ PMD_LOG_DEBUG(DRV, "Successfully clear src vsi");
+ }
+
+l_free:
ret = sxe2_vsi_destroy(adapter, adapter->vsi_ctxt.main_vsi);
if (ret) {
PMD_LOG_ERR(DRV, "Failed to del vsi from fw, ret=%d", ret);
goto l_end;
}
+ RTE_TAILQ_FOREACH_SAFE(var, &adapter->vsi_ctxt.other_vsi_list, next, tvar) {
+ ret = sxe2_vsi_destroy(adapter, var);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to del vsi from fw, ret=%d", ret);
+ break;
+ }
+ }
PMD_LOG_DEBUG(DRV, "vsi destroyed.");
l_end:
return;
}
+
+int32_t sxe2_vsi_repr_main_vsi_create(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter,
+ uint16_t repr_id)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_vsi *vsi = NULL;
+ struct sxe2_vsi *pos;
+ int32_t ret = 0;
+
+ TAILQ_FOREACH(pos, &parent_adapter->vsi_ctxt.other_vsi_list, next) {
+ if (pos->vsi_type == SXE2_VSI_T_DPDK_ESW) {
+ vsi = pos;
+ break;
+ }
+ }
+
+ if (vsi == NULL) {
+ PMD_LOG_ERR(INIT, "Failed to get dpdk vsi.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ TAILQ_INIT(&adapter->vsi_ctxt.other_vsi_list);
+
+ adapter->vsi_ctxt.vsi_type = SXE2_VSI_T_DPDK_ESW;
+ adapter->vsi_ctxt.kernel_vsi_id = SXE2_INVALID_VSI_ID;
+
+ adapter->cdev = parent_adapter->cdev;
+
+ adapter->q_ctxt.base_idx_in_pf = vsi->txqs.base_idx_in_func +
+ RTE_MIN(vsi->txqs.q_cnt, repr_id);
+ adapter->irq_ctxt.base_idx_in_func = vsi->irqs.base_idx_in_pf +
+ RTE_MIN(vsi->irqs.avail_cnt, repr_id);
+ adapter->q_ctxt.qp_cnt_assign = RTE_MIN(vsi->txqs.q_cnt, 1);
+ adapter->irq_ctxt.max_cnt_hw = RTE_MIN(vsi->irqs.avail_cnt, 1);
+
+ adapter->vsi_ctxt.main_vsi =
+ sxe2_vsi_node_create(adapter, vsi->vsi_id, SXE2_VSI_T_DPDK_ESW);
+ if (adapter->vsi_ctxt.main_vsi == NULL) {
+ ret = -ENOMEM;
+ PMD_LOG_ERR(DRV, "Failed to create vsi struct, ret=%d", ret);
+ goto l_end;
+ }
+ adapter->vsi_ctxt.dpdk_vsi_id = adapter->vsi_ctxt.main_vsi->vsi_id;
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+void sxe2_vsi_repr_main_vsi_destroy(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ sxe2_vsi_node_free(adapter->vsi_ctxt.main_vsi);
+}
diff --git a/drivers/net/sxe2/sxe2_vsi.h b/drivers/net/sxe2/sxe2_vsi.h
index 1d74c3262f..d4b2cd6554 100644
--- a/drivers/net/sxe2/sxe2_vsi.h
+++ b/drivers/net/sxe2/sxe2_vsi.h
@@ -193,13 +193,23 @@ struct sxe2_vsi_context {
uint16_t bond_member_dpdk_vsi_id[SXE2_MAX_BOND_MEMBER_CNT];
struct sxe2_vsi *main_vsi;
+
+ struct sxe2_vsi_list_head other_vsi_list;
};
void sxe2_sw_vsi_ctx_hw_cap_set(struct sxe2_adapter *adapter,
- struct sxe2_drv_vsi_caps *vsi_caps);
+ struct sxe2_drv_vsi_caps *vsi_caps);
+
+int32_t sxe2_other_vsi_create(struct sxe2_adapter *adapter, uint16_t cnt_vf);
int32_t sxe2_vsi_init(struct rte_eth_dev *dev);
void sxe2_vsi_uninit(struct rte_eth_dev *dev);
+int32_t sxe2_vsi_repr_main_vsi_create(struct rte_eth_dev *dev,
+ struct sxe2_adapter *parent_adapter,
+ uint16_t repr_id);
+
+void sxe2_vsi_repr_main_vsi_destroy(struct rte_eth_dev *dev);
+
#endif /* SXE2_VSI_H */
--
2.52.0
^ permalink raw reply related
* [PATCH v14 15/20] common/sxe2: add shared SFP module definitions
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch adds a new shared header file 'sxe2_msg.h' which
contains definitions for SFP/SFP+ modules. This file is shared across
Firmware, Kernel driver, and DPDK PMD to ensure consistent protocol
handling.
The header includes:
- SFP EEPROM memory map offsets.
- Module type encoding definitions.
By using this shared header, the PMD can correctly identify module
capabilities and report diagnostic information in a way that is
consistent with the underlying firmware logic.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/common/sxe2/sxe2_msg.h | 118 +++++++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)
create mode 100644 drivers/common/sxe2/sxe2_msg.h
diff --git a/drivers/common/sxe2/sxe2_msg.h b/drivers/common/sxe2/sxe2_msg.h
new file mode 100644
index 0000000000..f08944f7c9
--- /dev/null
+++ b/drivers/common/sxe2/sxe2_msg.h
@@ -0,0 +1,118 @@
+
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_MSG_H__
+#define __SXE2_MSG_H__
+
+enum sfp_type_identifier {
+ SXE2_SFP_TYPE_UNKNOWN = 0x00,
+ SXE2_SFP_TYPE_SFP = 0x03,
+
+ SXE2_SFP_TYPE_QSFP_PLUS = 0x0D,
+ SXE2_SFP_TYPE_QSFP28 = 0x11,
+
+ SXE2_SFP_TYPE_MAX = 0xFF,
+};
+
+#ifndef SFP_DEFINE
+#define SFP_DEFINE
+
+#define SXE2_SFP_EEP_WR 0x1
+#define SXE2_SFP_EEP_QSFP 0x1
+
+enum sfp_bus_addr {
+ SXE2_SFP_EEP_I2C_ADDR0 = 0xA0,
+ SXE2_SFP_EEP_I2C_ADDR1 = 0xA2,
+ SXE2_SFP_EEP_I2C_ADDR_NR = 0xFFFF,
+};
+
+struct sxe2_sfp_req {
+ uint8_t is_wr;
+ uint8_t is_qsfp;
+ uint16_t bus_addr;
+ uint16_t page_cnt;
+ uint16_t offset;
+ uint16_t data_len;
+ uint16_t rvd;
+ uint8_t data[];
+};
+
+struct sxe2_sfp_resp {
+ uint8_t is_wr;
+ uint8_t is_qsfp;
+ uint16_t data_len;
+ uint8_t data[];
+};
+
+enum sfp_page_cnt {
+ SXE2_SFP_EEP_PAGE_CNT0 = 0,
+ SXE2_SFP_EEP_PAGE_CNT1,
+ SXE2_SFP_EEP_PAGE_CNT2,
+ SXE2_SFP_EEP_PAGE_CNT3,
+ SXE2_SFP_EEP_PAGE_CNT20 = 20,
+ SXE2_SFP_EEP_PAGE_CNT21 = 21,
+
+ SXE2_SFP_EEP_PAGE_CNT_NR = 0xFFFF,
+};
+
+#define SXE2_SFP_E2P_I2C_7BIT_ADDR0 (SXE2_SFP_EEP_I2C_ADDR0 >> 1)
+#define SXE2_SFP_E2P_I2C_7BIT_ADDR1 (SXE2_SFP_EEP_I2C_ADDR1 >> 1)
+
+#define SXE2_QSFP_PAGE_OFST_START 128
+#define SXE2_SFP_EEP_OFST_MAX 255
+#define SXE2_SFP_EEP_LEN_MAX 256
+#endif
+
+#ifndef FW_STATE_DEFINE
+#define FW_STATE_DEFINE
+
+#define SXE2_FW_STATUS_MAIN_SHIF (16)
+#define SXE2_FW_STATUS_MAIN_MASK (0xFF0000)
+#define SXE2_FW_STATUS_SUB_MASK (0xFFFF)
+
+enum Sxe2FwStateMain {
+ SXE2_FW_STATE_MAIN_UNDEFINED = 0x00,
+ SXE2_FW_STATE_MAIN_INIT = 0x10000,
+ SXE2_FW_STATE_MAIN_RUN = 0x20000,
+ SXE2_FW_STATE_MAIN_ABNOMAL = 0x30000,
+};
+
+enum Sxe2FwState {
+ SXE2_FW_START_STATE_UNDEFINED = SXE2_FW_STATE_MAIN_UNDEFINED,
+ SXE2_FW_START_STATE_INIT_BASE = (SXE2_FW_STATE_MAIN_INIT + 0x1),
+ SXE2_FW_START_STATE_SCAN_DEVICE = (SXE2_FW_STATE_MAIN_INIT + 0x20),
+ SXE2_FW_START_STATE_FINISHED = (SXE2_FW_STATE_MAIN_RUN + 0x0),
+ SXE2_FW_START_STATE_UPGRADE = (SXE2_FW_STATE_MAIN_RUN + 0x1),
+ SXE2_FW_START_STATE_SYNC = (SXE2_FW_STATE_MAIN_RUN + 0x2),
+ SXE2_FW_RUNNING_STATE_ABNOMAL = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x1),
+ SXE2_FW_RUNNING_STATE_ABNOMAL_CORE1 = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x2),
+ SXE2_FW_RUNNING_STATE_ABNOMAL_HEART = (SXE2_FW_STATE_MAIN_ABNOMAL + 0x3),
+ SXE2_FW_START_STATE_MASK = (SXE2_FW_STATUS_MAIN_MASK | SXE2_FW_STATUS_SUB_MASK),
+};
+#endif
+
+#ifndef LED_DEFINE
+#define LED_DEFINE
+
+enum sxe2_led_mode {
+ SXE2_IDENTIFY_LED_BLINK_ON = 0,
+ SXE2_IDENTIFY_LED_BLINK_OFF,
+ SXE2_IDENTIFY_LED_ON,
+ SXE2_IDENTIFY_LED_OFF,
+ SXE2_IDENTIFY_LED_RESET,
+};
+
+
+typedef struct sxe2_led_ctrl {
+ uint32_t mode;
+ uint32_t duration;
+} sxe2_led_ctrl_s;
+
+typedef struct sxe2_led_ctrl_resp {
+ uint32_t ack;
+} sxe2_led_ctrl_resp_s;
+#endif
+
+#endif /* __SXE2_MSG_H__ */
--
2.52.0
^ permalink raw reply related
* [PATCH v14 07/20] net/sxe2: support IPsec inline protocol offload
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch adds support for IPsec inline protocol offload for both
inbound and outbound traffic.
- Implement rte_security_ops: session_create, session_destroy.
- Add hardware SA table management.
- Update Rx/Tx data path to handle security offload flags.
The hardware offloads the ESP encapsulation/decapsulation and
cryptographic processing.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 2 +
drivers/net/sxe2/sxe2_cmd_chnl.c | 197 ++++
drivers/net/sxe2/sxe2_cmd_chnl.h | 20 +
drivers/net/sxe2/sxe2_drv_cmd.h | 61 ++
drivers/net/sxe2/sxe2_ethdev.c | 14 +
drivers/net/sxe2/sxe2_ethdev.h | 3 +
drivers/net/sxe2/sxe2_ipsec.c | 1565 +++++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_ipsec.h | 254 +++++
drivers/net/sxe2/sxe2_rx.c | 5 +
drivers/net/sxe2/sxe2_security.c | 335 ++++++
drivers/net/sxe2/sxe2_security.h | 77 ++
drivers/net/sxe2/sxe2_tx.c | 8 +
drivers/net/sxe2/sxe2_txrx_poll.c | 55 +
13 files changed, 2596 insertions(+)
create mode 100644 drivers/net/sxe2/sxe2_ipsec.c
create mode 100644 drivers/net/sxe2/sxe2_ipsec.h
create mode 100644 drivers/net/sxe2/sxe2_security.c
create mode 100644 drivers/net/sxe2/sxe2_security.h
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index f03ea15356..86973edc99 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -64,4 +64,6 @@ sources += files(
'sxe2_filter.c',
'sxe2_rss.c',
'sxe2_tm.c',
+ 'sxe2_ipsec.c',
+ 'sxe2_security.c',
)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 19323ffcc4..7711e8e57d 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -877,3 +877,200 @@ int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter)
l_end:
return ret;
}
+
+
+int32_t sxe2_drv_ipsec_get_capa(struct sxe2_adapter *adapter)
+{
+ int32_t ret = -1;
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_drv_ipsec_capa_resq resp;
+ struct sxe2_common_device *cdev = adapter->cdev;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_CAP_GET,
+ NULL, 0,
+ &resp, sizeof(resp));
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to get ipsec specifications, ret=%d", ret);
+ goto l_end;
+ }
+
+ adapter->security_ctx.ipsec_ctx.max_tx_sa = rte_le_to_cpu_16(resp.tx_sa_cnt);
+ adapter->security_ctx.ipsec_ctx.max_rx_sa = rte_le_to_cpu_16(resp.rx_sa_cnt);
+ adapter->security_ctx.ipsec_ctx.max_tcam = rte_le_to_cpu_16(resp.ip_id_cnt);
+ adapter->security_ctx.ipsec_ctx.max_udp_group = rte_le_to_cpu_16(resp.udp_group_cnt);
+
+ PMD_DEV_LOG_INFO(adapter, DRV, "Max tx sa:%u, max rx sa:%u, max tcam:%u, udp group:%u.",
+ rte_le_to_cpu_16(resp.tx_sa_cnt),
+ rte_le_to_cpu_16(resp.rx_sa_cnt),
+ rte_le_to_cpu_16(resp.ip_id_cnt),
+ rte_le_to_cpu_16(resp.udp_group_cnt));
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_ipsec_resource_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = -1;
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_RESOURCE_CLEAR,
+ NULL, 0,
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to clear ipsec resource, ret=%d", ret);
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_ipsec_txsa_add(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_tx_sa *tx_sa)
+{
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_drv_ipsec_txsa_add_req req = { 0 };
+ struct sxe2_drv_ipsec_txsa_add_resp resp = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+ uint32_t mode = 0;
+ uint32_t i = 0;
+
+ if (tx_sa->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+ mode |= IPSEC_TX_ENGINE_SM4;
+ if (tx_sa->mode == SXE2_IPSEC_MODE_ENC_AND_AUTH)
+ mode |= IPSEC_TX_ENCRYPT;
+ req.mode = rte_cpu_to_le_32(mode);
+ for (i = 0; i < SXE2_IPSEC_KEY_LEN; i++) {
+ req.encrypt_keys[i] = tx_sa->enc_key[i];
+ req.auth_keys[i] = tx_sa->auth_key[i];
+ }
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_TXSA_ADD,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to add tx sa, ret=%d", ret);
+ goto l_end;
+ }
+ tx_sa->hw_sa_id = rte_le_to_cpu_16(resp.index);
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_ipsec_rxsa_add(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_rx_sa *rx_sa,
+ struct sxe2_ipsec_rx_tcam *rx_tcam,
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group)
+{
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_drv_ipsec_rxsa_add_req req = { 0 };
+ struct sxe2_drv_ipsec_rxsa_add_resp resp = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+ uint32_t mode = 0;
+ uint32_t i = 0;
+
+ if (rx_sa->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+ mode |= IPSEC_RX_ENGINE_SM4;
+ if (rx_sa->mode == SXE2_IPSEC_MODE_ENC_AND_AUTH)
+ mode |= IPSEC_RX_DECRYPT;
+ if (rx_tcam->ip_addr.type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
+ mode |= IPSEC_RX_IPV6;
+ memcpy(req.ipaddr, rx_tcam->ip_addr.dst_ipv6, sizeof(req.ipaddr));
+ } else {
+ req.ipaddr[0] = rx_tcam->ip_addr.dst_ipv4;
+ }
+ req.mode = rte_cpu_to_le_32(mode);
+ req.spi = rte_cpu_to_le_32(rx_sa->spi);
+ if (rx_udp_group != NULL) {
+ req.udp_port = rte_cpu_to_le_32((uint32_t)rx_udp_group->udp_port);
+ req.sport_en = rx_udp_group->sport_en;
+ req.dport_en = rx_udp_group->dport_en;
+ }
+
+ PMD_DEV_LOG_INFO(adapter, DRV, "Add rx sa, mode: 0x%x, spi: 0x%x, udp_port: %u, "
+ "sport_en: %u, dport_en: %u.",
+ req.mode, req.spi, req.udp_port, req.sport_en, req.dport_en);
+
+ /* encrypt and auth keys */
+ for (i = 0; i < SXE2_IPSEC_KEY_LEN; i++) {
+ req.encrypt_keys[i] = rx_sa->enc_key[i];
+ req.auth_keys[i] = rx_sa->auth_key[i];
+ }
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_RXSA_ADD,
+ &req, sizeof(req),
+ &resp, sizeof(resp));
+
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add rx sa, ret=%d", ret);
+ goto l_end;
+ }
+ rx_sa->hw_sa_id = rte_le_to_cpu_16(resp.sa_idx);
+ rx_sa->hw_ip_id = resp.ip_id;
+ rx_tcam->hw_ip_id = resp.ip_id;
+ rx_sa->hw_udp_group_id = resp.udp_group_id;
+ if (rx_udp_group != NULL)
+ rx_udp_group->hw_group_id = resp.udp_group_id;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_drv_ipsec_rxsa_delete(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_rx_sa *rx_sa)
+{
+ struct sxe2_drv_ipsec_rxsa_del_req req = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ req.sa_idx = rte_cpu_to_le_16(rx_sa->hw_sa_id);
+ req.spi = rte_cpu_to_le_32(rx_sa->spi);
+ req.ip_id = rx_sa->hw_ip_id;
+ req.group_id = rx_sa->hw_udp_group_id;
+
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_RXSA_DEL,
+ &req, sizeof(req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to delete rx sa, sa id: %u, spi: %u, "
+ "ip id: %u, udp group id: %u, ret: %d.",
+ rx_sa->hw_sa_id, rx_sa->spi, rx_sa->hw_ip_id,
+ rx_sa->hw_udp_group_id, ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
+ uint16_t sa_id)
+{
+ struct sxe2_drv_ipsec_txsa_del_req req = { 0 };
+ struct sxe2_drv_cmd_params cmd = { 0 };
+ struct sxe2_common_device *cdev = adapter->cdev;
+ int32_t ret = -1;
+
+ req.sa_idx = rte_cpu_to_le_16(sa_id);
+ sxe2_drv_cmd_params_fill(adapter, &cmd, SXE2_DRV_CMD_IPSEC_TXSA_DEL,
+ &req, sizeof(req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, &cmd);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to delete tx sa, sa id: %u, ret: %d.",
+ sa_id, ret);
+
+ return ret;
+}
+
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index 77e689abcd..dac487fe7d 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -44,6 +44,26 @@ int32_t sxe2_drv_root_tree_alloc(struct rte_eth_dev *dev);
int32_t sxe2_drv_tm_commit(struct sxe2_adapter *adapter);
+int32_t sxe2_drv_ipsec_resource_clear(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_ipsec_get_capa(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_ipsec_rxsa_add(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_rx_sa *rx_sa,
+ struct sxe2_ipsec_rx_tcam *rx_tcam,
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group);
+
+int32_t sxe2_drv_ipsec_txsa_add(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_tx_sa *tx_sa);
+
+int32_t sxe2_drv_ipsec_rxsa_delete(struct sxe2_adapter *adapter,
+ struct sxe2_ipsec_rx_sa *rx_sa);
+
+int32_t sxe2_drv_ipsec_txsa_delete(struct sxe2_adapter *adapter,
+ uint16_t sa_id);
+
+int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+
int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index 67c6885cae..39a108d76a 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -375,6 +375,67 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_tm_add_queue_msg {
struct sxe2_tm_info info;
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_capa_resq {
+ uint16_t tx_sa_cnt;
+ uint16_t rx_sa_cnt;
+ uint16_t ip_id_cnt;
+ uint16_t udp_group_cnt;
+} __rte_packed_end;
+
+#define SXE2_IPSEC_KEY_LEN (32)
+#define SXE2_IPV6_ADDR_LEN (4)
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_txsa_add_req {
+ uint32_t mode;
+ uint8_t encrypt_keys[SXE2_IPSEC_KEY_LEN];
+ uint8_t auth_keys[SXE2_IPSEC_KEY_LEN];
+ bool func_type;
+ uint8_t func_id;
+ uint8_t drv_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_txsa_add_resp {
+ uint16_t index;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_rxsa_add_req {
+ uint32_t mode;
+ uint32_t spi;
+ uint32_t ipaddr[SXE2_IPV6_ADDR_LEN];
+ uint32_t udp_port;
+ uint8_t sport_en;
+ uint8_t dport_en;
+ uint8_t is_over_sdn;
+ uint8_t sdn_group_id;
+ uint8_t encrypt_keys[SXE2_IPSEC_KEY_LEN];
+ uint8_t auth_keys[SXE2_IPSEC_KEY_LEN];
+ bool func_type;
+ uint8_t func_id;
+ uint8_t drv_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_rxsa_add_resp {
+ uint8_t ip_id;
+ uint8_t udp_group_id;
+ uint16_t sa_idx;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_txsa_del_req {
+ uint16_t sa_idx;
+ bool func_type;
+ uint8_t func_id;
+ uint8_t drv_id;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_ipsec_rxsa_del_req {
+ uint8_t ip_id;
+ uint8_t group_id;
+ uint16_t sa_idx;
+ uint32_t spi;
+ bool func_type;
+ uint8_t func_id;
+ uint8_t drv_id;
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index f98cf367f1..9c9d98782b 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -298,6 +298,11 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_PTP)
dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP;
+ if (sxe2_ipsec_supported(adapter)) {
+ dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SECURITY;
+ dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_SECURITY;
+ }
+
if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) {
dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
dev_info->flow_type_rss_offloads |= SXE2_RSS_HF_SUPPORT_ALL;
@@ -1053,6 +1058,12 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto init_eth_err;
}
+ ret = sxe2_security_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize security, ret=%d", ret);
+ goto init_security_err;
+ }
+
ret = sxe2_rss_disable(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to disable rss, ret=%d", ret);
@@ -1067,6 +1078,8 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
goto l_end;
+init_security_err:
+ sxe2_eth_uinit(dev);
init_sched_err:
init_rss_err:
init_eth_err:
@@ -1085,6 +1098,7 @@ static int32_t sxe2_dev_close(struct rte_eth_dev *dev)
(void)sxe2_rss_disable(dev);
(void)sxe2_sched_uinit(dev);
sxe2_vsi_uninit(dev);
+ sxe2_security_uinit(dev);
sxe2_dev_pci_map_uinit(dev);
sxe2_eth_uinit(dev);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 95594fcbde..fed8ce37d9 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -20,6 +20,8 @@
#include "sxe2_queue.h"
#include "sxe2_mac.h"
#include "sxe2_osal.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
#include "sxe2_tm.h"
#include "sxe2_filter.h"
@@ -313,6 +315,7 @@ struct sxe2_adapter {
struct sxe2_sched_hw_cap sched_ctxt;
struct sxe2_tm_context tm_ctxt;
struct sxe2_devargs devargs;
+ struct sxe2_security_ctx security_ctx;
struct sxe2_switchdev_info switchdev_info;
bool rule_started;
bool flow_isolated;
diff --git a/drivers/net/sxe2/sxe2_ipsec.c b/drivers/net/sxe2/sxe2_ipsec.c
new file mode 100644
index 0000000000..e783a51b85
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ipsec.c
@@ -0,0 +1,1565 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_malloc.h>
+#include <rte_bitmap.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
+#include "sxe2_cmd_chnl.h"
+#include "sxe2_common_log.h"
+
+bool sxe2_ipsec_supported(struct sxe2_adapter *adapter)
+{
+ uint64_t cap = adapter->cap_flags;
+
+ return !!(cap & SXE2_DEV_CAPS_OFFLOAD_IPSEC);
+}
+
+bool sxe2_ipsec_valid_tx_offloads(uint64_t offloads)
+{
+ bool ret = true;
+ uint64_t tso_features = 0;
+ uint64_t cksum_features = 0;
+
+ if (offloads & RTE_ETH_TX_OFFLOAD_SECURITY) {
+ tso_features = RTE_ETH_TX_OFFLOAD_TCP_TSO |
+ RTE_ETH_TX_OFFLOAD_UDP_TSO |
+ RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO |
+ RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
+ if (offloads & tso_features) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with TSO offload.");
+ ret = false;
+ goto l_end;
+ }
+
+ cksum_features = RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_UDP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_TCP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_SCTP_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
+ if (offloads & cksum_features) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with checksum offload.");
+ ret = false;
+ goto l_end;
+ }
+
+ if (offloads & (RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_QINQ_INSERT)) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with vlan offload.");
+ ret = false;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+bool sxe2_ipsec_valid_rx_offloads(uint64_t offloads)
+{
+ bool ret = true;
+
+ if (offloads & RTE_ETH_RX_OFFLOAD_SECURITY) {
+ if (offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with LRO offload.");
+ ret = false;
+ goto l_end;
+ }
+
+ if (offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with checksum offload.");
+ ret = false;
+ goto l_end;
+ }
+
+ if (offloads & RTE_ETH_RX_OFFLOAD_KEEP_CRC) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with keep CRC offload.");
+ ret = false;
+ goto l_end;
+ }
+
+ if (offloads & RTE_ETH_RX_OFFLOAD_VLAN) {
+ PMD_LOG_ERR(DRV, "Security offload is not compatible with vlan offload.");
+ ret = false;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_ipsec_bitmap_mem_init(struct rte_bitmap **d_bmp, void **d_mem, uint32_t bits)
+{
+ struct rte_bitmap *bmp = NULL;
+ uint32_t bmp_size = 0;
+ void *mem = NULL;
+ int32_t ret = -1;
+
+ bmp_size = rte_bitmap_get_memory_footprint(bits);
+
+ mem = rte_zmalloc("ipsec bitmap", bmp_size, RTE_CACHE_LINE_SIZE);
+ if (mem == NULL) {
+ PMD_LOG_ERR(DRV, "Alloc ipsec bitmap memory failed.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ bmp = rte_bitmap_init(bits, mem, bmp_size);
+ if (bmp == NULL) {
+ PMD_LOG_ERR(DRV, "Failed to init ipsec bitmap.");
+ rte_free(mem);
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ *d_bmp = bmp;
+ *d_mem = mem;
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_ipsec_bitmap_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+ int32_t ret = -1;
+
+ ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp,
+ &sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem, sxe2_sctx->ipsec_ctx.max_tx_sa);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp,
+ &sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem, sxe2_sctx->ipsec_ctx.max_rx_sa);
+ if (ret) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp,
+ &sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem, sxe2_sctx->ipsec_ctx.max_tcam);
+ if (ret) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+ sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_bitmap_mem_init(&sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp,
+ &sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem, sxe2_sctx->ipsec_ctx.max_udp_group);
+ if (ret) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+ sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+ sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+ sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static uint16_t sxe2_ipsec_id_alloc(struct rte_bitmap *bmp, uint16_t bits)
+{
+ uint16_t i = 0;
+ uint16_t index = 0XFFFF;
+
+ for (i = 0; i < bits; i++) {
+ if (!rte_bitmap_get(bmp, i)) {
+ index = i;
+ rte_bitmap_set(bmp, i);
+ break;
+ }
+ }
+
+ return index;
+}
+
+static void sxe2_ipsec_id_free(struct rte_bitmap *bmp, uint16_t pos)
+{
+ rte_bitmap_clear(bmp, pos);
+}
+
+static struct rte_cryptodev_symmetric_capability *
+sxe2_ipsec_cipher_cap_get(struct rte_cryptodev_capabilities *crypto_cap,
+ enum rte_crypto_cipher_algorithm algo)
+{
+ struct rte_cryptodev_symmetric_capability *capability = NULL;
+ uint8_t index = 0;
+
+ for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+ if (crypto_cap[index].sym.xform_type == RTE_CRYPTO_SYM_XFORM_CIPHER &&
+ crypto_cap[index].sym.cipher.algo == algo) {
+ capability = &crypto_cap[index].sym;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return capability;
+}
+
+static struct rte_cryptodev_symmetric_capability *
+sxe2_ipsec_auth_cap_get(struct rte_cryptodev_capabilities *crypto_cap,
+ enum rte_crypto_auth_algorithm algo)
+{
+ struct rte_cryptodev_symmetric_capability *capability = NULL;
+ uint8_t index = 0;
+
+ for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+ if (crypto_cap[index].sym.xform_type == RTE_CRYPTO_SYM_XFORM_AUTH &&
+ crypto_cap[index].sym.auth.algo == algo) {
+ capability = &crypto_cap[index].sym;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return capability;
+}
+
+static bool sxe2_security_valid_key(uint16_t src_key, uint16_t max_key,
+ uint16_t min_key, uint16_t increment)
+{
+ bool is_valid = false;
+
+ if (src_key > SXE2_IPSEC_MAX_KEY_LEN) {
+ is_valid = false;
+ goto l_end;
+ }
+
+ if (src_key < min_key || src_key > max_key) {
+ is_valid = false;
+ goto l_end;
+ }
+
+ if (increment == 0) {
+ is_valid = true;
+ goto l_end;
+ }
+
+ if ((uint16_t)(src_key - min_key) % increment) {
+ is_valid = false;
+ goto l_end;
+ }
+
+ is_valid = true;
+
+l_end:
+ return is_valid;
+}
+
+static int32_t
+sxe2_ipsec_valid_cipher(enum rte_crypto_cipher_operation cipher_op,
+ struct rte_cryptodev_capabilities *crypto_cap,
+ struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *capability = NULL;
+ uint16_t src_key = 0;
+ uint16_t max_key = 0;
+ uint16_t min_key = 0;
+ uint16_t increment = 0;
+ int32_t ret = -1;
+
+ if (xform->cipher.op != cipher_op) {
+ PMD_LOG_ERR(DRV, "Invalid cipher direction specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ capability = sxe2_ipsec_cipher_cap_get(crypto_cap, xform->cipher.algo);
+ if (!capability) {
+ PMD_LOG_ERR(DRV, "Invalid cipher algo specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ src_key = xform->cipher.key.length;
+ min_key = capability->cipher.key_size.min;
+ max_key = capability->cipher.key_size.max;
+ increment = capability->cipher.key_size.increment;
+ if (!sxe2_security_valid_key(src_key, max_key, min_key, increment)) {
+ PMD_LOG_ERR(DRV, "Invalid cipher key size specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_valid_auth(enum rte_crypto_auth_operation auth_op,
+ struct rte_cryptodev_capabilities *crypto_cap,
+ struct rte_crypto_sym_xform *xform)
+{
+ const struct rte_cryptodev_symmetric_capability *capability = NULL;
+ uint16_t src_key = 0;
+ uint16_t max_key = 0;
+ uint16_t min_key = 0;
+ uint16_t increment = 0;
+ int32_t ret = -1;
+
+ if (xform->auth.op != auth_op) {
+ PMD_LOG_ERR(DRV, "Invalid auth direction specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ capability = sxe2_ipsec_auth_cap_get(crypto_cap, xform->auth.algo);
+ if (!capability) {
+ PMD_LOG_ERR(DRV, "Invalid auth algo specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ src_key = xform->auth.key.length;
+ min_key = capability->auth.key_size.min;
+ max_key = capability->auth.key_size.max;
+ increment = capability->auth.key_size.increment;
+ if (!sxe2_security_valid_key(src_key, max_key, min_key, increment)) {
+ PMD_LOG_ERR(DRV, "Invalid auth key size specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static bool
+sxe2_ipsec_valid_algo(enum rte_crypto_auth_algorithm auth_algo,
+ enum rte_crypto_cipher_algorithm cipher_algo)
+{
+ bool ret = false;
+
+ if ((cipher_algo == SXE2_RTE_CRYPTO_CIPHER_AES_CBC &&
+ auth_algo == SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC) ||
+ (cipher_algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC &&
+ auth_algo == SXE2_RTE_CRYPTO_AUTH_SM3_HMAC)) {
+ ret = true;
+ goto l_end;
+ }
+
+l_end:
+ return ret;
+}
+
+static enum sxe2_ipsec_algorithm
+sxe2_ipsec_algo_gen(enum rte_crypto_cipher_algorithm cipher_algo)
+{
+ enum sxe2_ipsec_algorithm algo = SXE2_IPSEC_ALGO_INVALID;
+
+ if (cipher_algo == SXE2_RTE_CRYPTO_CIPHER_AES_CBC)
+ algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+ else if (cipher_algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+ algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+
+ return algo;
+}
+
+static int32_t
+ sxe2_ipsec_valid_xform(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf)
+{
+ struct rte_crypto_sym_xform *xform = NULL;
+ struct rte_cryptodev_capabilities *crypto_cap =
+ sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].crypto_capabilities;
+ enum rte_crypto_auth_algorithm auth_algo = RTE_CRYPTO_AUTH_NULL;
+ enum rte_crypto_cipher_algorithm cipher_algo = RTE_CRYPTO_CIPHER_NULL;
+ int32_t ret = -1;
+
+ if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
+ conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+ xform = conf->crypto_xform;
+ cipher_algo = xform->cipher.algo;
+ ret = sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_ENCRYPT,
+ crypto_cap, xform);
+ if (ret)
+ goto l_end;
+
+ if (conf->crypto_xform->next) {
+ if (conf->crypto_xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+ auth_algo = conf->crypto_xform->next->auth.algo;
+ if (!sxe2_ipsec_valid_algo(auth_algo, cipher_algo)) {
+ PMD_LOG_ERR(DRV, "Invalid algo group.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ xform = conf->crypto_xform->next;
+ ret = sxe2_ipsec_valid_auth(RTE_CRYPTO_AUTH_OP_GENERATE,
+ crypto_cap, xform);
+ if (ret)
+ goto l_end;
+ } else {
+ PMD_LOG_ERR(DRV, "Encrypt direction next xform only verify.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ } else if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+ conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+ xform = conf->crypto_xform;
+ ret = sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_DECRYPT,
+ crypto_cap, xform);
+ if (ret)
+ goto l_end;
+
+ } else if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+ conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+ xform = conf->crypto_xform;
+ ret = sxe2_ipsec_valid_auth(RTE_CRYPTO_AUTH_OP_VERIFY, crypto_cap, xform);
+ if (ret)
+ goto l_end;
+
+ if (conf->crypto_xform->next &&
+ conf->crypto_xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+ auth_algo = conf->crypto_xform->auth.algo;
+ cipher_algo = conf->crypto_xform->next->cipher.algo;
+ if (!sxe2_ipsec_valid_algo(auth_algo, cipher_algo)) {
+ PMD_LOG_ERR(DRV, "Invalid algo group.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ xform = conf->crypto_xform->next;
+ ret = sxe2_ipsec_valid_cipher(RTE_CRYPTO_CIPHER_OP_DECRYPT,
+ crypto_cap, xform);
+ if (ret)
+ goto l_end;
+ } else {
+ PMD_LOG_ERR(DRV, "Not support decrypt direction only verify, but not decrypt.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ } else {
+ PMD_LOG_ERR(DRV, "Encrypt/decrypt xform invalid.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_valid_udp(struct rte_security_session_conf *conf)
+{
+ int32_t ret = -1;
+ uint16_t sport = conf->ipsec.udp.sport;
+ uint16_t dport = conf->ipsec.udp.dport;
+
+ if (conf->ipsec.options.udp_encap == 0) {
+ ret = 0;
+ goto l_end;
+ }
+
+ if (sport == 0 && dport == 0) {
+ PMD_LOG_ERR(DRV, "Invalid udp port, cannot be zero.");
+ ret = -1;
+ goto l_end;
+ }
+
+ if (sport != 0 && dport != 0 && sport != dport) {
+ PMD_LOG_ERR(DRV, "Invalid udp port, if sport and dport is not zero, must be equal.");
+ ret = -1;
+ goto l_end;
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_session_conf_valid(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf)
+{
+ int32_t ret = -1;
+
+ if (sxe2_sctx == NULL) {
+ PMD_LOG_ERR(DRV, "Invalid security ctx.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->action_type !=
+ sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].action) {
+ PMD_LOG_ERR(DRV, "Invalid action specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->ipsec.mode !=
+ sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].ipsec.mode) {
+ PMD_LOG_ERR(DRV, "Invalid IPsec mode specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->ipsec.proto !=
+ sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC].ipsec.proto) {
+ PMD_LOG_ERR(DRV, "Invalid IPsec protocol specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->ipsec.options.esn) {
+ PMD_LOG_ERR(DRV, "Not support esn.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS &&
+ conf->ipsec.spi == 0) {
+ PMD_LOG_ERR(DRV, "spi cannot be zero.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (conf->crypto_xform == NULL) {
+ PMD_LOG_ERR(DRV, "Invalid ipsec xform specified");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_valid_udp(conf);
+ if (ret)
+ goto l_end;
+
+ ret = sxe2_ipsec_valid_xform(sxe2_sctx, conf);
+ if (ret)
+ goto l_end;
+
+l_end:
+ return ret;
+}
+
+static void
+sxe2_ipsec_session_save(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess, uint16_t sa_id, uint16_t index)
+{
+ enum rte_crypto_cipher_algorithm cipher_algo = RTE_CRYPTO_CIPHER_NULL;
+
+ sxe2_sess->adapter = sxe2_sctx->adapter;
+ sxe2_sess->direction = conf->ipsec.direction;
+ sxe2_sess->protocol = conf->protocol;
+ sxe2_sess->mode = conf->ipsec.mode;
+ sxe2_sess->sa_proto = conf->ipsec.proto;
+ sxe2_sess->sa.spi = conf->ipsec.spi;
+ sxe2_sess->sa.hw_idx = sa_id;
+ sxe2_sess->sa.sw_idx = index;
+
+ if (conf->ipsec.options.esn) {
+ sxe2_sess->esn.enabled = true;
+ sxe2_sess->esn.value = conf->ipsec.esn.value;
+ }
+
+ if (sxe2_sess->mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL)
+ sxe2_sess->type = conf->ipsec.tunnel.type;
+
+ if (conf->ipsec.options.udp_encap) {
+ sxe2_sess->udp_cap.enabled = true;
+ memcpy(&sxe2_sess->udp_cap.value, &conf->ipsec.udp,
+ sizeof(struct rte_security_ipsec_udp_param));
+ }
+
+ sxe2_sess->pkt_metadata_template.sa_idx = sa_id;
+ sxe2_sess->pkt_metadata_template.ol_flags |= SXE2_IPSEC_OL_FLAGS_IS_TUN;
+ sxe2_sess->pkt_metadata_template.ol_flags |= SXE2_IPSEC_OL_FLAGS_IS_ESP;
+
+ if (conf->ipsec.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS &&
+ conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+ cipher_algo = conf->crypto_xform->cipher.algo;
+ sxe2_sess->pkt_metadata_template.algo = sxe2_ipsec_algo_gen(cipher_algo);
+ if (conf->crypto_xform->next)
+ sxe2_sess->pkt_metadata_template.mode = SXE2_IPSEC_MODE_ENC_AND_AUTH;
+ else
+ sxe2_sess->pkt_metadata_template.mode = SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+ }
+
+ PMD_LOG_INFO(DRV,
+ "Save security info to session ctx, said:%u, spi:%u, mode:%u, algo:%u",
+ sa_id, sxe2_sess->sa.spi,
+ sxe2_sess->pkt_metadata_template.mode,
+ sxe2_sess->pkt_metadata_template.algo);
+}
+
+static void
+sxe2_ipsec_tx_sa_fill(struct sxe2_ipsec_tx_sa *tx_sa,
+ struct rte_security_session_conf *conf)
+{
+ uint8_t *dst = NULL;
+ uint8_t len = 0;
+
+ memcpy(&tx_sa->xform, &conf->ipsec, sizeof(struct rte_security_ipsec_xform));
+
+ if (conf->crypto_xform->next)
+ tx_sa->mode = SXE2_IPSEC_MODE_ENC_AND_AUTH;
+ else
+ tx_sa->mode = SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+
+ if (conf->crypto_xform->cipher.algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+ tx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+ else
+ tx_sa->algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+
+ dst = tx_sa->enc_key;
+ len = conf->crypto_xform->cipher.key.length;
+ memcpy(dst, conf->crypto_xform->cipher.key.data, len);
+
+ if (conf->crypto_xform->next) {
+ dst = tx_sa->auth_key;
+ len = conf->crypto_xform->next->auth.key.length;
+ memcpy(dst, conf->crypto_xform->next->auth.key.data, len);
+ }
+}
+
+static int32_t
+sxe2_ipsec_tx_sa_add(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess)
+{
+ struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+ struct rte_bitmap *bmp = sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp;
+ uint16_t bits = sxe2_sctx->ipsec_ctx.max_tx_sa;
+ uint16_t index = 0xFFFF;
+ int32_t ret = -1;
+
+ rte_spinlock_lock(&sxe2_sctx->security_lock);
+ index = sxe2_ipsec_id_alloc(bmp, bits);
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+ if (index == 0xFFFF) {
+ PMD_LOG_ERR(DRV, "Failed to allocate ipsec tx sa index.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ tx_sa = &sxe2_sctx->ipsec_ctx.tx_sa[index];
+
+ sxe2_ipsec_tx_sa_fill(tx_sa, conf);
+
+ ret = sxe2_drv_ipsec_txsa_add(sxe2_sctx->adapter, tx_sa);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to add tx sa.");
+ ret = -EIO;
+ rte_spinlock_lock(&sxe2_sctx->security_lock);
+ sxe2_ipsec_id_free(bmp, index);
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+ goto l_end;
+ }
+
+ sxe2_ipsec_session_save(sxe2_sctx, conf, sxe2_sess, tx_sa->hw_sa_id, tx_sa->id);
+
+ PMD_LOG_INFO(DRV, "Add tx sa success, tx sa id: %u, index: %u.",
+ tx_sa->hw_sa_id, tx_sa->id);
+
+l_end:
+ return ret;
+}
+
+static uint16_t
+sxe2_ipsec_tcam_id_find(struct sxe2_ipsec_rx_tcam *rx_tcam,
+ struct rte_security_ipsec_tunnel_param tunnel, uint16_t len)
+{
+ struct sxe2_ipsec_rx_tcam *per = NULL;
+ uint16_t tcam_id = 0XFFFF;
+ uint16_t i = 0;
+
+ for (i = 0; i < len; i++) {
+ per = &rx_tcam[i];
+ if (per->ip_addr.type == tunnel.type) {
+ if (tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4 &&
+ per->ip_addr.dst_ipv4 == (uint32_t)tunnel.ipv4.dst_ip.s_addr) {
+ tcam_id = i;
+ goto l_end;
+ }
+ if (tunnel.type == RTE_SECURITY_IPSEC_TUNNEL_IPV6) {
+ if (!memcmp(&tunnel.ipv6, &per->ip_addr.dst_ipv6,
+ sizeof(tunnel.ipv6))) {
+ tcam_id = i;
+ goto l_end;
+ }
+ }
+ }
+ }
+
+l_end:
+ return tcam_id;
+}
+
+static uint16_t
+sxe2_ipsec_group_id_find(struct sxe2_ipsec_rx_udp_group *rx_udp_group,
+ uint16_t udp_port, uint8_t sport_en, uint8_t dport_en, uint16_t len)
+{
+ struct sxe2_ipsec_rx_udp_group *per = NULL;
+ uint16_t group_id = 0XFFFF;
+ uint16_t i;
+
+ for (i = 0; i < len; i++) {
+ per = &rx_udp_group[i];
+ if (per->udp_port == udp_port && per->sport_en == sport_en &&
+ per->dport_en == dport_en) {
+ group_id = i;
+ goto l_end;
+ }
+ }
+
+l_end:
+ return group_id;
+}
+
+static void
+sxe2_ipsec_rx_sa_fill(struct sxe2_ipsec_rx_sa *rx_sa,
+ struct rte_security_session_conf *conf)
+{
+ uint8_t *dst = NULL;
+ uint8_t len = 0;
+
+ memcpy(&rx_sa->xform, &conf->ipsec, sizeof(struct rte_security_ipsec_xform));
+
+ if (conf->crypto_xform->next)
+ rx_sa->mode = SXE2_IPSEC_MODE_ENC_AND_AUTH;
+ else
+ rx_sa->mode = SXE2_IPSEC_MODE_ONLY_ENCRYPT;
+
+ if (conf->crypto_xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+ if (conf->crypto_xform->cipher.algo == SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC)
+ rx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+ else
+ rx_sa->algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+ } else {
+ if (conf->crypto_xform->auth.algo == SXE2_RTE_CRYPTO_AUTH_SM3_HMAC)
+ rx_sa->algo = SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC;
+ else
+ rx_sa->algo = SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC;
+ }
+
+ if (conf->crypto_xform->next) {
+ dst = rx_sa->auth_key;
+ len = conf->crypto_xform->auth.key.length;
+ memcpy(dst, conf->crypto_xform->auth.key.data, len);
+
+ dst = rx_sa->enc_key;
+ len = conf->crypto_xform->next->cipher.key.length;
+ memcpy(dst, conf->crypto_xform->next->cipher.key.data, len);
+ } else {
+ dst = rx_sa->enc_key;
+ len = conf->crypto_xform->cipher.key.length;
+ memcpy(dst, conf->crypto_xform->cipher.key.data, len);
+ }
+
+ rx_sa->spi = conf->ipsec.spi;
+}
+
+static int32_t
+sxe2_ipsec_rx_tcam_fill(struct sxe2_security_ctx *sxe2_sctx, uint16_t *tcam_id,
+ struct rte_security_session_conf *conf)
+{
+ int32_t ret = -1;
+ uint16_t len = sxe2_sctx->ipsec_ctx.max_tcam;
+ struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+
+ *tcam_id = sxe2_ipsec_tcam_id_find(sxe2_sctx->ipsec_ctx.rx_tcam,
+ conf->ipsec.tunnel, len);
+ if (*tcam_id == 0XFFFF) {
+ *tcam_id = sxe2_ipsec_id_alloc(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp, len);
+ if (*tcam_id == 0xFFFF) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[*tcam_id];
+
+ rx_tcam->ip_addr.type = conf->ipsec.tunnel.type;
+ if (rx_tcam->ip_addr.type == RTE_SECURITY_IPSEC_TUNNEL_IPV4) {
+ rx_tcam->ip_addr.dst_ipv4 = (uint32_t)conf->ipsec.tunnel.ipv4.dst_ip.s_addr;
+ } else {
+ memcpy(&rx_tcam->ip_addr.dst_ipv6, &conf->ipsec.tunnel.ipv6.dst_addr,
+ sizeof(rx_tcam->ip_addr.dst_ipv6));
+ }
+ } else {
+ rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[*tcam_id];
+ }
+ rx_tcam->ref_cnt++;
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_udp_group_fill(struct sxe2_security_ctx *sxe2_sctx, uint16_t *udp_group_id,
+ struct rte_security_session_conf *conf)
+{
+ int32_t ret = -1;
+ uint16_t len = sxe2_sctx->ipsec_ctx.max_udp_group;
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+ uint8_t sport_en = 0;
+ uint8_t dport_en = 0;
+ uint16_t udp_port = 0;
+
+ if (!conf->ipsec.options.udp_encap) {
+ ret = 0;
+ goto l_end;
+ }
+
+ if (conf->ipsec.udp.sport) {
+ sport_en = 1;
+ udp_port = conf->ipsec.udp.sport;
+ } else {
+ sport_en = 0;
+ }
+ if (conf->ipsec.udp.dport) {
+ dport_en = 1;
+ udp_port = conf->ipsec.udp.dport;
+ } else {
+ dport_en = 0;
+ }
+
+ *udp_group_id = sxe2_ipsec_group_id_find(sxe2_sctx->ipsec_ctx.rx_udp_group,
+ udp_port, sport_en, dport_en, len);
+ if (*udp_group_id == 0XFFFF) {
+ *udp_group_id = sxe2_ipsec_id_alloc(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp, len);
+ if (*udp_group_id == 0xFFFF) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rx_udp_group = &sxe2_sctx->ipsec_ctx.rx_udp_group[*udp_group_id];
+ rx_udp_group->sport_en = sport_en;
+ rx_udp_group->dport_en = dport_en;
+ rx_udp_group->udp_port = udp_port;
+ } else {
+ rx_udp_group = &sxe2_sctx->ipsec_ctx.rx_udp_group[*udp_group_id];
+ }
+ rx_udp_group->ref_cnt++;
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_sa_add(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess)
+{
+ struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+ struct sxe2_ipsec_rx_sa *rx_sa = NULL;
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+ struct rte_bitmap *rx_sa_bmp = sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp;
+ struct rte_bitmap *rx_tcam_bmp = sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp;
+ uint16_t sa_bits = sxe2_sctx->ipsec_ctx.max_rx_sa;
+ uint16_t sa_id = 0xFFFF;
+ uint16_t tcam_id = 0xFFFF;
+ uint16_t udp_group_id = 0xFFFF;
+ int32_t ret = -1;
+
+ rte_spinlock_lock(&sxe2_sctx->security_lock);
+ sa_id = sxe2_ipsec_id_alloc(rx_sa_bmp, sa_bits);
+ if (sa_id == 0xFFFF) {
+ PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx sa index.");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ rx_sa = &sxe2_sctx->ipsec_ctx.rx_sa[sa_id];
+ sxe2_ipsec_rx_sa_fill(rx_sa, conf);
+
+ ret = sxe2_ipsec_rx_tcam_fill(sxe2_sctx, &tcam_id, conf);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx tcam index.");
+ sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+ goto l_end;
+ }
+ rx_sa->tcam_id = tcam_id;
+ rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[tcam_id];
+
+ ret = sxe2_ipsec_rx_udp_group_fill(sxe2_sctx, &udp_group_id, conf);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to allocate ipsec rx udp group index.");
+ sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+ sxe2_ipsec_id_free(rx_tcam_bmp, tcam_id);
+ goto l_end;
+ }
+
+ if (udp_group_id != 0XFFFF) {
+ rx_sa->udp_group_id = (uint8_t)udp_group_id;
+ rx_udp_group = &sxe2_sctx->ipsec_ctx.rx_udp_group[udp_group_id];
+ } else {
+ rx_sa->udp_group_id = 0XFF;
+ }
+
+ ret = sxe2_drv_ipsec_rxsa_add(sxe2_sctx->adapter, rx_sa, rx_tcam, rx_udp_group);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Failed to add rx sa.");
+ sxe2_ipsec_id_free(rx_sa_bmp, sa_id);
+ rx_tcam->ref_cnt--;
+ if (rx_tcam->ref_cnt == 0)
+ sxe2_ipsec_id_free(rx_tcam_bmp, tcam_id);
+
+ if (rx_udp_group != NULL) {
+ rx_udp_group->ref_cnt--;
+ if (rx_udp_group->ref_cnt == 0)
+ sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp,
+ udp_group_id);
+ }
+
+ ret = -EIO;
+ goto l_end;
+ }
+
+ sxe2_ipsec_session_save(sxe2_sctx, conf, sxe2_sess, rx_sa->hw_sa_id, rx_sa->id);
+
+ PMD_LOG_INFO(DRV, "Add rx sa success, rx sa id: %u, rx ip id: %u, group id: %u, index: %u.",
+ rx_sa->hw_sa_id, rx_sa->hw_ip_id, rx_sa->udp_group_id, rx_sa->id);
+
+l_end:
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_hw_table_add(struct sxe2_security_ctx *sxe2_sctx,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess)
+{
+ int32_t ret = -1;
+
+ switch (conf->ipsec.direction) {
+ case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
+ ret = sxe2_ipsec_tx_sa_add(sxe2_sctx, conf, sxe2_sess);
+ break;
+ case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
+ ret = sxe2_ipsec_rx_sa_add(sxe2_sctx, conf, sxe2_sess);
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "Invalid sa direction.");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int sxe2_ipsec_session_create(void *device,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ int32_t ret = -1;
+
+ ret = sxe2_ipsec_session_conf_valid(sxe2_sctx, conf);
+ if (ret) {
+ PMD_LOG_ERR(DRV, "Input ipsec session conf invalid.");
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_hw_table_add(sxe2_sctx, conf, sxe2_sess);
+ if (ret)
+ goto l_end;
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_tx_sa_delete(struct sxe2_security_ctx *sxe2_sctx,
+ struct sxe2_security_session *sxe2_sess)
+{
+ struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+ uint16_t sa_id = sxe2_sess->sa.hw_idx;
+ uint16_t sw_sa_id = sxe2_sess->sa.sw_idx;
+ int32_t ret = -1;
+
+ if (sw_sa_id >= sxe2_sctx->ipsec_ctx.max_tx_sa) {
+ ret = 0;
+ PMD_LOG_WARN(DRV, "invalid sw sa id: %u.", sw_sa_id);
+ goto l_end;
+ }
+
+ if (!rte_bitmap_get(sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp, sw_sa_id)) {
+ ret = 0;
+ PMD_LOG_WARN(DRV, "bitmap not set, index: %u.", sw_sa_id);
+ goto l_end;
+ }
+
+ tx_sa = &sxe2_sctx->ipsec_ctx.tx_sa[sw_sa_id];
+
+ if (tx_sa->hw_sa_id != sa_id) {
+ ret = 0;
+ PMD_LOG_WARN(DRV, "invalid hw sa id: %u != %u.", sa_id, tx_sa->hw_sa_id);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_ipsec_txsa_delete(sxe2_sctx->adapter, sa_id);
+ if (ret)
+ goto l_end;
+
+ rte_spinlock_lock(&sxe2_sctx->security_lock);
+ sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_bmp, sw_sa_id);
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_rx_sa_delete(struct sxe2_security_ctx *sxe2_sctx,
+ struct sxe2_security_session *sxe2_sess)
+{
+ struct sxe2_ipsec_rx_udp_group *rx_udp = NULL;
+ struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+ struct sxe2_ipsec_rx_sa *rx_sa = NULL;
+ uint16_t sa_id = sxe2_sess->sa.hw_idx;
+ uint16_t sw_sa_id = sxe2_sess->sa.sw_idx;
+ int32_t ret = -1;
+
+ if (sw_sa_id >= sxe2_sctx->ipsec_ctx.max_rx_sa) {
+ ret = 0;
+ PMD_LOG_WARN(DRV, "invalid sw sa id: %u.", sw_sa_id);
+ goto l_end;
+ }
+
+ if (!rte_bitmap_get(sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp, sw_sa_id)) {
+ ret = 0;
+ PMD_LOG_INFO(DRV, "bitmap not set, id: %u.", sw_sa_id);
+ goto l_end;
+ }
+
+ rx_sa = &sxe2_sctx->ipsec_ctx.rx_sa[sw_sa_id];
+
+ if (rx_sa->hw_sa_id != sa_id) {
+ ret = 0;
+ PMD_LOG_WARN(DRV, "invalid hw sa id: %u != %u.", sa_id, rx_sa->hw_sa_id);
+ goto l_end;
+ }
+
+ ret = sxe2_drv_ipsec_rxsa_delete(sxe2_sctx->adapter, rx_sa);
+ if (ret)
+ goto l_end;
+
+ rte_spinlock_lock(&sxe2_sctx->security_lock);
+ sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_bmp, sw_sa_id);
+
+ rx_tcam = &sxe2_sctx->ipsec_ctx.rx_tcam[rx_sa->tcam_id];
+ rx_tcam->ref_cnt--;
+ if (rx_tcam->ref_cnt == 0)
+ sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_bmp, rx_sa->tcam_id);
+
+ if (rx_sa->udp_group_id == 0xFF) {
+ PMD_LOG_INFO(DRV, "Not need to release udp group resource.");
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+ goto l_end;
+ }
+ rx_udp = &sxe2_sctx->ipsec_ctx.rx_udp_group[rx_sa->udp_group_id];
+ rx_udp->ref_cnt--;
+ if (rx_udp->ref_cnt == 0)
+ sxe2_ipsec_id_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_bmp, rx_sa->udp_group_id);
+ rte_spinlock_unlock(&sxe2_sctx->security_lock);
+
+l_end:
+ return ret;
+}
+
+static int32_t
+sxe2_ipsec_hw_table_delete(struct sxe2_security_ctx *sxe2_sctx,
+ struct sxe2_security_session *sxe2_sess)
+{
+ int32_t ret = -1;
+
+ switch (sxe2_sess->direction) {
+ case RTE_SECURITY_IPSEC_SA_DIR_EGRESS:
+ ret = sxe2_ipsec_tx_sa_delete(sxe2_sctx, sxe2_sess);
+ break;
+ case RTE_SECURITY_IPSEC_SA_DIR_INGRESS:
+ ret = sxe2_ipsec_rx_sa_delete(sxe2_sctx, sxe2_sess);
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "Invalid sa direction.");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int sxe2_ipsec_session_destroy(void *device, struct rte_security_session *session)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ struct sxe2_security_session *sxe2_sess = NULL;
+ sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+ int32_t ret = -1;
+
+ if (unlikely(sxe2_sess == NULL || sxe2_sess->adapter != adapter)) {
+ PMD_LOG_ERR(DRV, "Invalid device adapter.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_hw_table_delete(sxe2_sctx, sxe2_sess);
+ if (ret) {
+ ret = -EIO;
+ PMD_LOG_ERR(DRV, "Failed to delete ipsec hw tables.");
+ goto l_end;
+ }
+
+ memset(sxe2_sess, 0, sizeof(struct sxe2_security_session));
+
+ PMD_LOG_INFO(DRV, "Delete ipsec session success, sa_id: %u, spi: %u.",
+ sxe2_sess->sa.hw_idx, sxe2_sess->sa.spi);
+
+l_end:
+ return ret;
+}
+
+int sxe2_ipsec_pkt_metadata_set(void *device, struct rte_security_session *session,
+ struct rte_mbuf *m, void *params)
+{
+ struct rte_eth_dev *eth_dev = (struct rte_eth_dev *)device;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev);
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ struct sxe2_security_session *sxe2_sess = NULL;
+ struct sxe2_ipsec_pkt_metadata *md = NULL;
+ uint16_t offset = 0;
+ int32_t ret = -1;
+
+ sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+ if (unlikely(sxe2_sess == NULL || sxe2_sess->adapter != adapter)) {
+ PMD_LOG_ERR(DRV, "Invalid parameters.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ offset = ((struct sxe2_ipsec_metadata_params *)params)->esp_header_offset;
+ if (offset <= IPSEC_ESP_OFFSET_MIN || offset >= IPSEC_ESP_OFFSET_MAX) {
+ PMD_LOG_ERR(DRV, "Invalid esp header offset.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ md = RTE_MBUF_DYNFIELD(m, sxe2_sctx->ipsec_ctx.md_offset, struct sxe2_ipsec_pkt_metadata *);
+
+ memcpy(md, &sxe2_sess->pkt_metadata_template, sizeof(struct sxe2_ipsec_pkt_metadata));
+ md->esp_head_offset = offset;
+
+ PMD_LOG_INFO(DRV, "ipsec metadata set, offset:%u, said:%u, mode:%u, algo:%u.", offset,
+ sxe2_sess->pkt_metadata_template.sa_idx, sxe2_sess->pkt_metadata_template.mode,
+ sxe2_sess->pkt_metadata_template.algo);
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+int sxe2_ipsec_pkt_md_offset_get(struct sxe2_adapter *adapter)
+{
+ return adapter->security_ctx.ipsec_ctx.md_offset;
+}
+
+static void sxe2_ipsec_enc_aes_cbc_fill(struct rte_cryptodev_capabilities *cap)
+{
+ cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cap->sym.cipher.algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC;
+
+ cap->sym.cipher.block_size = SXE2_SECURITY_BLOCK_SIZE_16;
+
+ cap->sym.cipher.key_size.min = SXE2_IPSEC_AES_KEY_MIN;
+ cap->sym.cipher.key_size.max = SXE2_IPSEC_AES_KEY_MAX;
+ cap->sym.cipher.key_size.increment = SXE2_IPSEC_AES_KEY_INC;
+
+ cap->sym.cipher.iv_size.min = SXE2_IPSEC_AES_IV_MIN;
+ cap->sym.cipher.iv_size.max = SXE2_IPSEC_AES_IV_MAX;
+ cap->sym.cipher.iv_size.increment = SXE2_IPSEC_AES_IV_INC;
+
+ cap->sym.cipher.dataunit_set |= RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES;
+}
+
+static void sxe2_ipsec_enc_sm4_cbc_fill(struct rte_cryptodev_capabilities *cap)
+{
+ cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+
+ cap->sym.cipher.algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC;
+
+ cap->sym.cipher.block_size = SXE2_SECURITY_BLOCK_SIZE_16;
+
+ cap->sym.cipher.key_size.min = SXE2_IPSEC_SM4_KEY_MIN;
+ cap->sym.cipher.key_size.max = SXE2_IPSEC_SM4_KEY_MAX;
+ cap->sym.cipher.key_size.increment = SXE2_IPSEC_SM4_KEY_INC;
+
+ cap->sym.cipher.iv_size.min = SXE2_IPSEC_SM4_IV_MIN;
+ cap->sym.cipher.iv_size.max = SXE2_IPSEC_SM4_IV_MAX;
+ cap->sym.cipher.iv_size.increment = SXE2_IPSEC_SM4_IV_INC;
+
+ cap->sym.cipher.dataunit_set |= RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES;
+}
+
+static void sxe2_ipsec_auth_sha_hmac_fill(struct rte_cryptodev_capabilities *cap)
+{
+ cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ cap->sym.auth.algo = SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC;
+
+ cap->sym.auth.block_size = SXE2_SECURITY_BLOCK_SIZE_64;
+
+ cap->sym.auth.key_size.min = SXE2_IPSEC_SHA_KEY_MIN;
+ cap->sym.auth.key_size.max = SXE2_IPSEC_SHA_KEY_MAX;
+ cap->sym.auth.key_size.increment = SXE2_IPSEC_SHA_KEY_INC;
+
+ cap->sym.auth.iv_size.min = SXE2_IPSEC_SHA_IV_MIN;
+ cap->sym.auth.iv_size.max = SXE2_IPSEC_SHA_IV_MAX;
+ cap->sym.auth.iv_size.increment = SXE2_IPSEC_SHA_IV_INC;
+
+ cap->sym.auth.digest_size.min = SXE2_IPSEC_SHA_DIGEST_MIN;
+ cap->sym.auth.digest_size.max = SXE2_IPSEC_SHA_DIGEST_MAX;
+ cap->sym.auth.digest_size.increment = SXE2_IPSEC_SHA_DIGEST_INC;
+
+ cap->sym.auth.aad_size.min = SXE2_IPSEC_AAD_MIN;
+ cap->sym.auth.aad_size.max = SXE2_IPSEC_AAD_MAX;
+ cap->sym.auth.aad_size.increment = SXE2_IPSEC_AAD_INC;
+}
+
+static void sxe2_ipsec_auth_sm3_hmac_fill(struct rte_cryptodev_capabilities *cap)
+{
+ cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AUTH;
+
+ cap->sym.auth.algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC;
+
+ cap->sym.auth.block_size = SXE2_SECURITY_BLOCK_SIZE_64;
+
+ cap->sym.auth.key_size.min = SXE2_IPSEC_SM3_KEY_MIN;
+ cap->sym.auth.key_size.max = SXE2_IPSEC_SM3_KEY_MAX;
+ cap->sym.auth.key_size.increment = SXE2_IPSEC_SM3_KEY_INC;
+
+ cap->sym.auth.iv_size.min = SXE2_IPSEC_SM3_IV_MIN;
+ cap->sym.auth.iv_size.max = SXE2_IPSEC_SM3_IV_MAX;
+ cap->sym.auth.iv_size.increment = SXE2_IPSEC_SM3_IV_INC;
+
+ cap->sym.auth.digest_size.min = SXE2_IPSEC_SM3_DIGEST_MIN;
+ cap->sym.auth.digest_size.max = SXE2_IPSEC_SM3_DIGEST_MAX;
+ cap->sym.auth.digest_size.increment = SXE2_IPSEC_SM3_DIGEST_INC;
+
+ cap->sym.auth.aad_size.min = SXE2_IPSEC_AAD_MIN;
+ cap->sym.auth.aad_size.max = SXE2_IPSEC_AAD_MAX;
+ cap->sym.auth.aad_size.increment = SXE2_IPSEC_AAD_INC;
+}
+
+static int32_t
+sxe2_ipsec_capabilities_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+ struct rte_cryptodev_capabilities *capabilities = NULL;
+ struct sxe2_security_capabilities *sxe2_cap =
+ &sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+ int32_t ret = -1;
+ uint8_t index = 0;
+
+ sxe2_cap->action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO;
+ sxe2_cap->ipsec.proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
+ sxe2_cap->ipsec.mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL;
+ sxe2_cap->ipsec.options.stats = 1;
+
+ capabilities = rte_zmalloc("security_caps",
+ sizeof(struct rte_cryptodev_capabilities) * SXE2_IPSEC_CAP_MAX, 0);
+ if (capabilities == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ for (index = 0; index < SXE2_IPSEC_CAP_MAX; index++) {
+ capabilities[index].op = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
+ switch (index) {
+ case SXE2_IPSEC_CAP_ENC_AES_CBC:
+ sxe2_ipsec_enc_aes_cbc_fill(&capabilities[index]);
+ break;
+ case SXE2_IPSEC_CAP_ENC_SM4_CBC:
+ sxe2_ipsec_enc_sm4_cbc_fill(&capabilities[index]);
+ break;
+ case SXE2_IPSEC_CAP_AUTH_SHA256_HMAC:
+ sxe2_ipsec_auth_sha_hmac_fill(&capabilities[index]);
+ break;
+ case SXE2_IPSEC_CAP_AUTH_SM3_HMAC:
+ sxe2_ipsec_auth_sm3_hmac_fill(&capabilities[index]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ sxe2_cap->crypto_capabilities = capabilities;
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+static void
+sxe2_ipsec_tx_sa_init(struct sxe2_ipsec_tx_sa *tx_sa, uint16_t len)
+{
+ struct sxe2_ipsec_tx_sa *per = NULL;
+ uint16_t i;
+
+ memset(tx_sa, 0, sizeof(struct sxe2_ipsec_tx_sa) * len);
+ for (i = 0; i < len; i++) {
+ per = &tx_sa[i];
+ per->id = i;
+ }
+}
+
+static void
+sxe2_ipsec_rx_sa_init(struct sxe2_ipsec_rx_sa *rx_sa, uint16_t len)
+{
+ struct sxe2_ipsec_rx_sa *per = NULL;
+ uint16_t i;
+
+ memset(rx_sa, 0, sizeof(struct sxe2_ipsec_rx_sa) * len);
+ for (i = 0; i < len; i++) {
+ per = &rx_sa[i];
+ per->id = i;
+ }
+}
+
+static void
+sxe2_ipsec_rx_tcam_init(struct sxe2_ipsec_rx_tcam *rx_tcam, uint16_t len)
+{
+ struct sxe2_ipsec_rx_tcam *per = NULL;
+ uint16_t i;
+
+ memset(rx_tcam, 0, sizeof(struct sxe2_ipsec_rx_tcam) * len);
+ for (i = 0; i < len; i++) {
+ per = &rx_tcam[i];
+ per->id = i;
+ }
+}
+
+static void
+sxe2_ipsec_rx_udp_group_init(struct sxe2_ipsec_rx_udp_group *rx_udp_group, uint16_t len)
+{
+ struct sxe2_ipsec_rx_udp_group *per = NULL;
+ uint16_t i;
+
+ memset(rx_udp_group, 0, sizeof(struct sxe2_ipsec_rx_udp_group) * len);
+ for (i = 0; i < len; i++) {
+ per = &rx_udp_group[i];
+ per->id = i;
+ }
+}
+
+static int32_t
+sxe2_ipsec_hw_table_init(struct sxe2_security_ctx *sxe2_sctx)
+{
+ struct sxe2_ipsec_tx_sa *tx_sa = NULL;
+ struct sxe2_ipsec_rx_sa *rx_sa = NULL;
+ struct sxe2_ipsec_rx_tcam *rx_tcam = NULL;
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group = NULL;
+ uint16_t max_tx_sa = sxe2_sctx->ipsec_ctx.max_tx_sa;
+ uint16_t max_rx_sa = sxe2_sctx->ipsec_ctx.max_rx_sa;
+ uint16_t max_tcam = sxe2_sctx->ipsec_ctx.max_tcam;
+ uint16_t max_udp_group = sxe2_sctx->ipsec_ctx.max_udp_group;
+ int32_t ret = -1;
+
+ tx_sa = rte_zmalloc("sxe2_ipsec_tx_sa", sizeof(struct sxe2_ipsec_tx_sa) * max_tx_sa, 0);
+ if (tx_sa == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ sxe2_ipsec_tx_sa_init(tx_sa, max_tx_sa);
+ sxe2_sctx->ipsec_ctx.tx_sa = tx_sa;
+
+ rx_sa = rte_zmalloc("sxe2_ipsec_rx_sa", sizeof(struct sxe2_ipsec_rx_sa) * max_rx_sa, 0);
+ if (rx_sa == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ sxe2_ipsec_rx_sa_init(rx_sa, max_rx_sa);
+ sxe2_sctx->ipsec_ctx.rx_sa = rx_sa;
+
+ rx_tcam = rte_zmalloc("sxe2_ipsec_rx_tcam",
+ sizeof(struct sxe2_ipsec_rx_tcam) * max_tcam, 0);
+ if (rx_tcam == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ sxe2_ipsec_rx_tcam_init(rx_tcam, max_tcam);
+ sxe2_sctx->ipsec_ctx.rx_tcam = rx_tcam;
+
+ rx_udp_group = rte_zmalloc("sxe2_ipsec_rx_udp_group",
+ sizeof(struct sxe2_ipsec_rx_udp_group) * max_udp_group, 0);
+ if (rx_udp_group == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ sxe2_ipsec_rx_udp_group_init(rx_udp_group, max_udp_group);
+ sxe2_sctx->ipsec_ctx.rx_udp_group = rx_udp_group;
+
+ ret = 0;
+
+l_end:
+ if (ret) {
+ if (tx_sa != NULL) {
+ rte_free(tx_sa);
+ sxe2_sctx->ipsec_ctx.tx_sa = NULL;
+ }
+ if (rx_sa != NULL) {
+ rte_free(rx_sa);
+ sxe2_sctx->ipsec_ctx.rx_sa = NULL;
+ }
+ if (rx_tcam != NULL) {
+ rte_free(rx_tcam);
+ sxe2_sctx->ipsec_ctx.rx_tcam = NULL;
+ }
+ if (rx_udp_group != NULL) {
+ rte_free(rx_udp_group);
+ sxe2_sctx->ipsec_ctx.rx_udp_group = NULL;
+ }
+ }
+ return ret;
+}
+
+int32_t sxe2_ipsec_init(struct sxe2_adapter *adapter)
+{
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ struct sxe2_security_capabilities *sxe2_cap = NULL;
+ int32_t ret = -1;
+ struct rte_mbuf_dynfield pkt_md_dynfield = {
+ .name = "sxe2_ipsec_pkt_metadata",
+ .size = sizeof(struct sxe2_ipsec_pkt_metadata),
+ .align = alignof(struct sxe2_ipsec_pkt_metadata)
+ };
+
+ PMD_LOG_INFO(INIT, "Init ipsec.");
+
+ sxe2_sctx->ipsec_ctx.md_offset = rte_mbuf_dynfield_register(&pkt_md_dynfield);
+ if (sxe2_sctx->ipsec_ctx.md_offset < 0) {
+ PMD_LOG_ERR(INIT, "Failed to register ipsec mbuf dynamic field.");
+ ret = -EIO;
+ goto l_end;
+ }
+
+ ret = sxe2_ipsec_capabilities_init(sxe2_sctx);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init ipsec capabilities.");
+ goto l_end;
+ }
+
+ ret = sxe2_drv_ipsec_get_capa(adapter);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to get ipsec capabilities.");
+ goto l_caps_free;
+ }
+
+ ret = sxe2_ipsec_bitmap_init(sxe2_sctx);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init ipsec bitmap.");
+ goto l_caps_free;
+ }
+
+ ret = sxe2_ipsec_hw_table_init(sxe2_sctx);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init ipsec hw table.");
+ goto l_bitmap_free;
+ }
+
+ goto l_end;
+
+l_bitmap_free:
+
+ if (sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem = NULL;
+ }
+l_caps_free:
+ sxe2_cap = &sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+ if (sxe2_cap->crypto_capabilities != NULL) {
+ rte_free(sxe2_cap->crypto_capabilities);
+ sxe2_cap->crypto_capabilities = NULL;
+ }
+l_end:
+ return ret;
+}
+
+void sxe2_ipsec_uinit(struct sxe2_adapter *adapter)
+{
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ struct sxe2_security_capabilities *sxe2_cap =
+ &sxe2_sctx->sxe2_capabilities[SXE2_SECURITY_PROTOCOL_IPSEC];
+ struct sxe2_ipsec_tx_sa *tx_sa = sxe2_sctx->ipsec_ctx.tx_sa;
+ struct sxe2_ipsec_rx_sa *rx_sa = sxe2_sctx->ipsec_ctx.rx_sa;
+ struct sxe2_ipsec_rx_tcam *rx_tcam = sxe2_sctx->ipsec_ctx.rx_tcam;
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group = sxe2_sctx->ipsec_ctx.rx_udp_group;
+
+ PMD_LOG_INFO(INIT, "Uinit ipsec.");
+
+ (void)sxe2_drv_ipsec_resource_clear(adapter);
+
+ if (sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.tx_sa_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_sa_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_tcam_mem = NULL;
+ }
+ if (sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem != NULL) {
+ rte_free(sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem);
+ sxe2_sctx->ipsec_ctx.bmp.rx_udp_mem = NULL;
+ }
+
+ if (tx_sa != NULL) {
+ rte_free(tx_sa);
+ sxe2_sctx->ipsec_ctx.tx_sa = NULL;
+ }
+ if (rx_sa != NULL) {
+ rte_free(rx_sa);
+ sxe2_sctx->ipsec_ctx.rx_sa = NULL;
+ }
+ if (rx_tcam != NULL) {
+ rte_free(rx_tcam);
+ sxe2_sctx->ipsec_ctx.rx_tcam = NULL;
+ }
+ if (rx_udp_group != NULL) {
+ rte_free(rx_udp_group);
+ sxe2_sctx->ipsec_ctx.rx_udp_group = NULL;
+ }
+
+ if (sxe2_cap->crypto_capabilities != NULL) {
+ rte_free(sxe2_cap->crypto_capabilities);
+ sxe2_cap->crypto_capabilities = NULL;
+ }
+}
diff --git a/drivers/net/sxe2/sxe2_ipsec.h b/drivers/net/sxe2/sxe2_ipsec.h
new file mode 100644
index 0000000000..02930ddb4f
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_ipsec.h
@@ -0,0 +1,254 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+#ifndef __SXE2_IPSEC_H__
+#define __SXE2_IPSEC_H__
+
+#include <rte_security.h>
+#include <rte_security_driver.h>
+
+struct sxe2_adapter;
+struct sxe2_security_session;
+
+#define SXE2_IPSEC_AES_KEY_MIN (32)
+#define SXE2_IPSEC_AES_KEY_MAX (32)
+#define SXE2_IPSEC_AES_KEY_INC (0)
+
+#define SXE2_IPSEC_SM4_KEY_MIN (16)
+#define SXE2_IPSEC_SM4_KEY_MAX (16)
+#define SXE2_IPSEC_SM4_KEY_INC (0)
+
+#define SXE2_IPSEC_SHA_KEY_MIN (32)
+#define SXE2_IPSEC_SHA_KEY_MAX (32)
+#define SXE2_IPSEC_SHA_KEY_INC (0)
+
+#define SXE2_IPSEC_SM3_KEY_MIN (32)
+#define SXE2_IPSEC_SM3_KEY_MAX (32)
+#define SXE2_IPSEC_SM3_KEY_INC (0)
+
+#define SXE2_IPSEC_AES_IV_MIN (16)
+#define SXE2_IPSEC_AES_IV_MAX (16)
+#define SXE2_IPSEC_AES_IV_INC (0)
+
+#define SXE2_IPSEC_SM4_IV_MIN (16)
+#define SXE2_IPSEC_SM4_IV_MAX (16)
+#define SXE2_IPSEC_SM4_IV_INC (0)
+
+#define SXE2_IPSEC_SHA_IV_MIN (0)
+#define SXE2_IPSEC_SHA_IV_MAX (32)
+#define SXE2_IPSEC_SHA_IV_INC (16)
+
+#define SXE2_IPSEC_SM3_IV_MIN (0)
+#define SXE2_IPSEC_SM3_IV_MAX (32)
+#define SXE2_IPSEC_SM3_IV_INC (16)
+
+#define SXE2_IPSEC_SHA_DIGEST_MIN (32)
+#define SXE2_IPSEC_SHA_DIGEST_MAX (32)
+#define SXE2_IPSEC_SHA_DIGEST_INC (0)
+
+#define SXE2_IPSEC_SM3_DIGEST_MIN (32)
+#define SXE2_IPSEC_SM3_DIGEST_MAX (32)
+#define SXE2_IPSEC_SM3_DIGEST_INC (0)
+
+#define SXE2_IPSEC_AAD_MIN (0)
+#define SXE2_IPSEC_AAD_MAX (0)
+#define SXE2_IPSEC_AAD_INC (0)
+
+#define SXE2_IPSEC_MAX_KEY_LEN (32)
+#define SXE2_IPSEC_MIN_KEY_LEN (0)
+
+#define SXE2_IPSEC_OL_FLAGS_IS_TUN (0x1 << 0)
+#define SXE2_IPSEC_OL_FLAGS_IS_ESP (0x1 << 1)
+
+#define SXE2_IPSEC_DEFAULT_SA_OFFSET (0)
+#define SXE2_IPSEC_DEFAULT_SA_LEN (1024)
+
+#define IPSEC_TX_ENCRYPT (RTE_BIT32(0))
+#define IPSEC_TX_ENGINE_SM4 (RTE_BIT32(1))
+
+#define IPSEC_RX_VALID (RTE_BIT32(0))
+#define IPSEC_RX_IPV6 (RTE_BIT32(2))
+#define IPSEC_RX_DECRYPT (RTE_BIT32(3))
+#define IPSEC_RX_ENGINE_SM4 (RTE_BIT32(4))
+
+#define IPSEC_IPV6_LEN (4)
+#define IPSEC_ESP_OFFSET_MIN (16)
+#define IPSEC_ESP_OFFSET_MAX (256)
+
+enum sxe2_ipsec_cap {
+ SXE2_IPSEC_CAP_ENC_AES_CBC = 0,
+ SXE2_IPSEC_CAP_ENC_SM4_CBC = 1,
+ SXE2_IPSEC_CAP_AUTH_SHA256_HMAC = 2,
+ SXE2_IPSEC_CAP_AUTH_SM3_HMAC = 3,
+ SXE2_IPSEC_CAP_MAX = 4,
+};
+
+enum sxe2_ipsec_icv_len {
+ SXE2_IPSEC_ICV_0_BYTES = 0,
+ SXE2_IPSEC_ICV_12_BYTES,
+ SXE2_IPSEC_ICV_16_BYTES,
+ SXE2_IPSEC_ICV_INVALID,
+};
+
+enum sxe2_ipsec_bypass_dir {
+ SXE2_IPSEC_BYPASS_DIR_RX = 0,
+ SXE2_IPSEC_BYPASS_DIR_TX,
+ SXE2_IPSEC_BYPASS_DIR_INVALID,
+};
+
+enum sxe2_ipsec_bypass_status {
+ SXE2_IPSEC_BYPASS_STATUS_DISABLE = 0,
+ SXE2_IPSEC_BYPASS_STATUS_ENABLE,
+ SXE2_IPSEC_BYPASS_STATUS_INVALID,
+};
+
+enum sxe2_ipsec_status {
+ SXE2_IPSEC_ENC_BYPASS = 0,
+ SXE2_IPSEC_ENC_ENABLE,
+ SXE2_IPSEC_ENC_INVALID,
+};
+
+enum sxe2_ipsec_mode {
+ SXE2_IPSEC_MODE_ENC_AND_AUTH = 0,
+ SXE2_IPSEC_MODE_ONLY_ENCRYPT,
+ SXE2_IPSEC_MODE_INVALID,
+};
+
+struct sxe2_ipsec_ip_param {
+ enum rte_security_ipsec_tunnel_type type;
+ union {
+ uint32_t dst_ipv4;
+ uint32_t dst_ipv6[IPSEC_IPV6_LEN];
+ };
+};
+
+enum sxe2_ipsec_algorithm {
+ SXE2_IPSEC_ALGO_AES_CBC_AND_SHA256_128_HMAC = 0,
+ SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC,
+ SXE2_IPSEC_ALGO_INVALID,
+};
+
+struct sxe2_ipsec_pkt_metadata {
+ uint16_t sa_idx;
+ uint16_t esp_head_offset;
+ uint8_t ol_flags;
+ uint8_t mode;
+ uint8_t algo;
+};
+
+struct sxe2_ipsec_bitmap {
+ struct rte_bitmap *tx_sa_bmp;
+ struct rte_bitmap *rx_sa_bmp;
+ struct rte_bitmap *rx_tcam_bmp;
+ struct rte_bitmap *rx_udp_bmp;
+ void *tx_sa_mem;
+ void *rx_sa_mem;
+ void *rx_tcam_mem;
+ void *rx_udp_mem;
+};
+
+struct sxe2_ipsec_security_sa {
+ uint32_t spi;
+ uint16_t hw_idx;
+ uint16_t sw_idx;
+};
+
+struct sxe2_ipsec_esn {
+ union {
+ uint64_t value;
+ struct {
+ uint32_t hi;
+ uint32_t low;
+ };
+ };
+ uint8_t enabled;
+};
+
+struct sxe2_ipsec_udp {
+ struct rte_security_ipsec_udp_param value;
+ uint8_t enabled;
+};
+
+struct sxe2_ipsec_tx_sa {
+ struct rte_security_ipsec_xform xform;
+ uint16_t id;
+ uint16_t hw_sa_id;
+ enum sxe2_ipsec_mode mode;
+ enum sxe2_ipsec_algorithm algo;
+ uint8_t enc_key[SXE2_IPSEC_MAX_KEY_LEN];
+ uint8_t auth_key[SXE2_IPSEC_MAX_KEY_LEN];
+};
+
+struct sxe2_ipsec_rx_sa {
+ struct rte_security_ipsec_xform xform;
+ uint32_t spi;
+ uint16_t id;
+ uint16_t hw_sa_id;
+ uint8_t hw_ip_id;
+ uint8_t hw_udp_group_id;
+ uint8_t tcam_id;
+ uint8_t udp_group_id;
+ uint8_t sdn_group_id;
+ enum sxe2_ipsec_mode mode;
+ enum sxe2_ipsec_algorithm algo;
+ uint8_t enc_key[SXE2_IPSEC_MAX_KEY_LEN];
+ uint8_t auth_key[SXE2_IPSEC_MAX_KEY_LEN];
+};
+
+struct sxe2_ipsec_rx_tcam {
+ struct sxe2_ipsec_ip_param ip_addr;
+ uint16_t id;
+ uint8_t hw_ip_id;
+ uint8_t ref_cnt;
+};
+
+struct sxe2_ipsec_rx_udp_group {
+ uint16_t udp_port;
+ uint8_t sport_en;
+ uint8_t dport_en;
+ uint8_t id;
+ uint8_t hw_group_id;
+ uint8_t ref_cnt;
+};
+
+struct sxe2_ipsec_ctx {
+ struct sxe2_ipsec_tx_sa *tx_sa;
+ struct sxe2_ipsec_rx_sa *rx_sa;
+ struct sxe2_ipsec_rx_tcam *rx_tcam;
+ struct sxe2_ipsec_rx_udp_group *rx_udp_group;
+ struct sxe2_ipsec_bitmap bmp;
+ int md_offset;
+ uint16_t max_tx_sa;
+ uint16_t max_rx_sa;
+ uint16_t max_tcam;
+ uint8_t max_udp_group;
+};
+
+struct sxe2_ipsec_metadata_params {
+ uint16_t esp_header_offset;
+ uint16_t reserved;
+};
+
+bool sxe2_ipsec_supported(struct sxe2_adapter *adapter);
+
+bool sxe2_ipsec_valid_tx_offloads(uint64_t offloads);
+
+bool sxe2_ipsec_valid_rx_offloads(uint64_t offloads);
+
+int sxe2_ipsec_pkt_md_offset_get(struct sxe2_adapter *adapter);
+
+int sxe2_ipsec_session_create(void *device,
+ struct rte_security_session_conf *conf,
+ struct sxe2_security_session *sxe2_sess);
+
+int sxe2_ipsec_session_destroy(void *device,
+ struct rte_security_session *session);
+
+int sxe2_ipsec_pkt_metadata_set(void *device, struct rte_security_session *session,
+ struct rte_mbuf *m, void *params);
+
+int32_t sxe2_ipsec_init(struct sxe2_adapter *adapter);
+
+void sxe2_ipsec_uinit(struct sxe2_adapter *adapter);
+
+#endif /* __SXE2_IPSEC_H__ */
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 28832d5f71..007192c7d8 100644
--- a/drivers/net/sxe2/sxe2_rx.c
+++ b/drivers/net/sxe2/sxe2_rx.c
@@ -294,6 +294,11 @@ int32_t __rte_cold sxe2_rx_queue_setup(struct rte_eth_dev *dev,
goto l_end;
}
+ if (!sxe2_ipsec_valid_rx_offloads(offloads)) {
+ ret = -EINVAL;
+ goto l_end;
+ }
+
rxq = sxe2_rx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
if (rxq == NULL) {
PMD_LOG_ERR(RX, "rx queue[%d] resource alloc failed", queue_idx);
diff --git a/drivers/net/sxe2/sxe2_security.c b/drivers/net/sxe2/sxe2_security.c
new file mode 100644
index 0000000000..bc59d1b880
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_security.c
@@ -0,0 +1,335 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_malloc.h>
+
+#include "sxe2_ethdev.h"
+#include "sxe2_security.h"
+#include "sxe2_ipsec.h"
+#include "sxe2_common_log.h"
+
+static unsigned int
+sxe2_security_session_size_get(void *device __rte_unused)
+{
+ return sizeof(struct sxe2_security_session);
+}
+
+static int
+sxe2_security_session_create(void *device,
+ struct rte_security_session_conf *conf,
+ struct rte_security_session *session)
+{
+ int32_t ret = -1;
+ struct sxe2_security_session *sxe2_sess = NULL;
+ sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+
+ switch (conf->protocol) {
+ case RTE_SECURITY_PROTOCOL_IPSEC:
+ ret = sxe2_ipsec_session_create(device, conf, sxe2_sess);
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "Invalid security protocol.");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+sxe2_security_session_destroy(void *device, struct rte_security_session *session)
+{
+ int32_t ret = -1;
+ struct sxe2_security_session *sxe2_sess = NULL;
+ sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+
+ switch (sxe2_sess->protocol) {
+ case RTE_SECURITY_PROTOCOL_IPSEC:
+ ret = sxe2_ipsec_session_destroy(device, session);
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "Invalid security protocol.");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+sxe2_security_pkt_metadata_set(void *device,
+ struct rte_security_session *session,
+ struct rte_mbuf *m, void *params)
+{
+ struct sxe2_security_session *sxe2_sess = NULL;
+ sxe2_sess = SECURITY_GET_SESS_PRIV(session);
+ int32_t ret = -1;
+
+ switch (sxe2_sess->protocol) {
+ case RTE_SECURITY_PROTOCOL_IPSEC:
+ ret = sxe2_ipsec_pkt_metadata_set(device, session, m, params);
+ break;
+ default:
+ PMD_LOG_ERR(DRV, "Invalid security protocol.");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct rte_security_capability *
+sxe2_security_capabilities_get(void *device __rte_unused)
+{
+ static const struct rte_cryptodev_capabilities
+ ipsec_crypto_capabilities[] = {
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+ {.cipher = {
+ .algo = SXE2_RTE_CRYPTO_CIPHER_AES_CBC,
+ .block_size = SXE2_SECURITY_BLOCK_SIZE_16,
+ .key_size = {
+ .min = SXE2_IPSEC_AES_KEY_MIN,
+ .max = SXE2_IPSEC_AES_KEY_MAX,
+ .increment = SXE2_IPSEC_AES_KEY_INC
+ },
+ .iv_size = {
+ .min = SXE2_IPSEC_AES_IV_MIN,
+ .max = SXE2_IPSEC_AES_IV_MAX,
+ .increment = SXE2_IPSEC_AES_IV_INC
+ },
+ .dataunit_set = RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES,
+ }, }
+ }, }
+ },
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+ {.cipher = {
+ .algo = SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC,
+ .block_size = SXE2_SECURITY_BLOCK_SIZE_16,
+ .key_size = {
+ .min = SXE2_IPSEC_SM4_KEY_MIN,
+ .max = SXE2_IPSEC_SM4_KEY_MAX,
+ .increment = SXE2_IPSEC_SM4_KEY_INC
+ },
+ .iv_size = {
+ .min = SXE2_IPSEC_SM4_IV_MIN,
+ .max = SXE2_IPSEC_SM4_IV_MAX,
+ .increment = SXE2_IPSEC_SM4_IV_INC
+ },
+ .dataunit_set = RTE_CRYPTO_CIPHER_DATA_UNIT_LEN_512_BYTES,
+ }, }
+ }, }
+ },
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+ {.auth = {
+ .algo = SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC,
+ .block_size = SXE2_SECURITY_BLOCK_SIZE_64,
+ .key_size = {
+ .min = SXE2_IPSEC_SHA_KEY_MIN,
+ .max = SXE2_IPSEC_SHA_KEY_MAX,
+ .increment = SXE2_IPSEC_SHA_KEY_INC
+ },
+ .digest_size = {
+ .min = SXE2_IPSEC_SHA_DIGEST_MIN,
+ .max = SXE2_IPSEC_SHA_DIGEST_MAX,
+ .increment = SXE2_IPSEC_SHA_DIGEST_INC
+ },
+ .iv_size = {
+ .min = SXE2_IPSEC_SHA_IV_MIN,
+ .max = SXE2_IPSEC_SHA_IV_MAX,
+ .increment = SXE2_IPSEC_SHA_IV_INC
+ },
+ .aad_size = {
+ .min = SXE2_IPSEC_AAD_MIN,
+ .max = SXE2_IPSEC_AAD_MAX,
+ .increment = SXE2_IPSEC_AAD_INC
+ }
+ }, }
+ }, }
+ },
+ {
+ .op = RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_AUTH,
+ {.auth = {
+ .algo = SXE2_RTE_CRYPTO_AUTH_SM3_HMAC,
+ .block_size = SXE2_SECURITY_BLOCK_SIZE_64,
+ .key_size = {
+ .min = SXE2_IPSEC_SM3_KEY_MIN,
+ .max = SXE2_IPSEC_SM3_KEY_MAX,
+ .increment = SXE2_IPSEC_SM3_KEY_INC
+ },
+ .digest_size = {
+ .min = SXE2_IPSEC_SM3_DIGEST_MIN,
+ .max = SXE2_IPSEC_SM3_DIGEST_MAX,
+ .increment = SXE2_IPSEC_SM3_DIGEST_INC
+ },
+ .iv_size = {
+ .min = SXE2_IPSEC_SM3_IV_MIN,
+ .max = SXE2_IPSEC_SM3_IV_MAX,
+ .increment = SXE2_IPSEC_SM3_IV_INC
+ },
+ .aad_size = {
+ .min = SXE2_IPSEC_AAD_MIN,
+ .max = SXE2_IPSEC_AAD_MAX,
+ .increment = SXE2_IPSEC_AAD_INC
+ }
+ }, }
+ }, }
+ },
+ {
+ .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
+ {.sym = {
+ .xform_type = RTE_CRYPTO_SYM_XFORM_NOT_SPECIFIED
+ }, }
+ }
+ };
+
+ static const struct rte_security_capability
+ sxe2_security_capabilities[] = {
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ {.ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_EGRESS,
+ .options = {
+ .esn = 0,
+ .udp_encap = 1,
+ .copy_dscp = 0,
+ .copy_flabel = 0,
+ .copy_df = 0,
+ .dec_ttl = 0,
+ .ecn = 0,
+ .stats = 1,
+ .iv_gen_disable = 0,
+ .tunnel_hdr_verify = 1,
+ .udp_ports_verify = 1,
+ .ip_csum_enable = 0,
+ .l4_csum_enable = 0,
+ .ip_reassembly_en = 0,
+ .ingress_oop = 0
+ } } },
+ .crypto_capabilities = ipsec_crypto_capabilities,
+ .ol_flags = RTE_SECURITY_TX_OLOAD_NEED_MDATA
+ },
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO,
+ .protocol = RTE_SECURITY_PROTOCOL_IPSEC,
+ {.ipsec = {
+ .proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP,
+ .mode = RTE_SECURITY_IPSEC_SA_MODE_TUNNEL,
+ .direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS,
+ .options = {
+ .esn = 0,
+ .udp_encap = 1,
+ .copy_dscp = 0,
+ .copy_flabel = 0,
+ .copy_df = 0,
+ .dec_ttl = 0,
+ .ecn = 0,
+ .stats = 1,
+ .iv_gen_disable = 0,
+ .tunnel_hdr_verify = 1,
+ .udp_ports_verify = 1,
+ .ip_csum_enable = 0,
+ .l4_csum_enable = 0,
+ .ip_reassembly_en = 0,
+ .ingress_oop = 0
+ } } },
+ .crypto_capabilities = ipsec_crypto_capabilities,
+ .ol_flags = 0
+ },
+ {
+ .action = RTE_SECURITY_ACTION_TYPE_NONE
+ }
+ };
+
+ return sxe2_security_capabilities;
+}
+
+static struct rte_security_ops sxe2_security_ops = {
+ .session_get_size = sxe2_security_session_size_get,
+ .session_create = sxe2_security_session_create,
+ .session_destroy = sxe2_security_session_destroy,
+ .set_pkt_metadata = sxe2_security_pkt_metadata_set,
+ .capabilities_get = sxe2_security_capabilities_get,
+};
+
+int32_t sxe2_security_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_security_ctx *sctx = NULL;
+ struct sxe2_security_ctx *sxe2_sctx = &adapter->security_ctx;
+ int32_t ret = -1;
+
+ if (!sxe2_ipsec_supported(adapter)) {
+ ret = 0;
+ PMD_LOG_INFO(INIT, "Not support security feature.");
+ goto l_end;
+ }
+
+ PMD_LOG_INFO(INIT, "Init security feature.");
+
+ sctx = rte_zmalloc("security_ctx", sizeof(struct rte_security_ctx), 0);
+ if (sctx == NULL) {
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ sctx->device = dev;
+ sctx->ops = &sxe2_security_ops;
+ sctx->sess_cnt = 0;
+ sctx->flags = 0;
+ dev->security_ctx = (void *)sctx;
+
+ rte_spinlock_init(&sxe2_sctx->security_lock);
+ sxe2_sctx->adapter = adapter;
+
+ if (sxe2_ipsec_supported(adapter)) {
+ ret = sxe2_ipsec_init(adapter);
+ if (ret) {
+ rte_free(sctx);
+ sctx = NULL;
+ dev->security_ctx = NULL;
+ goto l_end;
+ }
+ }
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+void sxe2_security_uinit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_security_ctx *sctx = dev->security_ctx;
+
+ if (!sxe2_ipsec_supported(adapter)) {
+ PMD_LOG_INFO(INIT, "Not support security feature.");
+ goto l_end;
+ }
+
+ PMD_LOG_INFO(INIT, "Uinit security feature.");
+
+ if (sctx != NULL) {
+ rte_free(sctx);
+ sctx = NULL;
+ }
+
+ sxe2_ipsec_uinit(adapter);
+
+l_end:
+ return;
+}
diff --git a/drivers/net/sxe2/sxe2_security.h b/drivers/net/sxe2/sxe2_security.h
new file mode 100644
index 0000000000..366c0614bd
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_security.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_SECURITY_H__
+#define __SXE2_SECURITY_H__
+
+#include <rte_security.h>
+#include <rte_cryptodev.h>
+#include <rte_security_driver.h>
+
+#include "sxe2_ipsec.h"
+
+#define SXE2_DEV_TO_SECURITY(eth) \
+ ((struct rte_security_ctx *)(((struct rte_eth_dev *)eth)->security_ctx))
+
+#define SXE2_RTE_CRYPTO_CIPHER_AES_CBC (RTE_CRYPTO_CIPHER_AES_CBC)
+
+#define SXE2_RTE_RTE_CRYPTO_CIPHER_SM4_CBC (RTE_CRYPTO_CIPHER_SM4_CBC)
+
+#define SXE2_RTE_CRYPTO_AUTH_SHA256_HMAC (RTE_CRYPTO_AUTH_SHA256_HMAC)
+
+#define SXE2_RTE_CRYPTO_AUTH_SM3_HMAC (RTE_CRYPTO_AUTH_SM3_HMAC)
+
+enum sxe2_security_protocol {
+ SXE2_SECURITY_PROTOCOL_IPSEC = 0,
+ SXE2_SECURITY_PROTOCOL_MAX = 1,
+};
+
+enum sxe2_security_xform {
+ SXE2_SECURITY_IPSEC_EN = 0,
+ SXE2_SECURITY_IPSEC_DE = 1,
+ SXE2_SECURITY_NUM_MAX = 2,
+};
+
+enum sxe2_security_block_size {
+ SXE2_SECURITY_BLOCK_SIZE_16 = 16,
+ SXE2_SECURITY_BLOCK_SIZE_64 = 64,
+};
+
+struct sxe2_security_ipsec_caps {
+ enum rte_security_ipsec_sa_protocol proto;
+ enum rte_security_ipsec_sa_mode mode;
+ struct rte_security_ipsec_sa_options options;
+};
+
+struct sxe2_security_capabilities {
+ struct rte_cryptodev_capabilities *crypto_capabilities;
+ enum rte_security_session_action_type action;
+ struct sxe2_security_ipsec_caps ipsec;
+};
+
+struct sxe2_security_session {
+ struct sxe2_adapter *adapter;
+ struct sxe2_ipsec_pkt_metadata pkt_metadata_template;
+ struct sxe2_ipsec_security_sa sa;
+ struct sxe2_ipsec_esn esn;
+ struct sxe2_ipsec_udp udp_cap;
+ enum rte_security_session_protocol protocol;
+ enum rte_security_ipsec_sa_direction direction;
+ enum rte_security_ipsec_sa_mode mode;
+ enum rte_security_ipsec_sa_protocol sa_proto;
+ enum rte_security_ipsec_tunnel_type type;
+};
+
+struct sxe2_security_ctx {
+ struct sxe2_adapter *adapter;
+ struct sxe2_security_capabilities sxe2_capabilities[SXE2_SECURITY_PROTOCOL_MAX];
+ struct sxe2_ipsec_ctx ipsec_ctx;
+ rte_spinlock_t security_lock;
+};
+
+int32_t sxe2_security_init(struct rte_eth_dev *dev);
+
+void sxe2_security_uinit(struct rte_eth_dev *dev);
+
+#endif /* __SXE2_SECURITY_H__ */
diff --git a/drivers/net/sxe2/sxe2_tx.c b/drivers/net/sxe2/sxe2_tx.c
index a280edc9c5..f49238ceef 100644
--- a/drivers/net/sxe2/sxe2_tx.c
+++ b/drivers/net/sxe2/sxe2_tx.c
@@ -304,6 +304,11 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev *dev,
}
offloads = tx_conf->offloads | dev->data->dev_conf.txmode.offloads;
+ if (!sxe2_ipsec_valid_tx_offloads(offloads)) {
+ ret = -EINVAL;
+ goto end;
+ }
+
txq = sxe2_tx_queue_alloc(dev, queue_idx, nb_desc, socket_id);
if (txq == NULL) {
PMD_LOG_ERR(TX, "failed to alloc sxe2vf tx queue:%u resource", queue_idx);
@@ -327,6 +332,9 @@ int32_t __rte_cold sxe2_tx_queue_setup(struct rte_eth_dev *dev,
txq->ops = sxe2_tx_default_ops_get();
txq->ops.queue_reset(txq);
+ if (sxe2_ipsec_supported(adapter) && txq->offloads & RTE_ETH_TX_OFFLOAD_SECURITY)
+ txq->ipsec_pkt_md_offset = sxe2_ipsec_pkt_md_offset_get(adapter);
+
dev->data->tx_queues[queue_idx] = txq;
ret = 0;
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index 3c6fe37404..8b6e585c36 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -307,6 +307,25 @@ static __rte_always_inline void sxe2_desc_tso_fill(struct rte_mbuf *tx_pkt,
return;
}
+static __rte_always_inline void sxe2_desc_ipsec_fill(struct rte_mbuf *tx_pkt,
+ struct sxe2_tx_queue *txq, uint16_t *ipsec_offset,
+ uint64_t *desc_type_cmd_tso_mss)
+{
+ struct sxe2_ipsec_pkt_metadata *md = NULL;
+ uint16_t ipsec_pkt_md_offset = txq->ipsec_pkt_md_offset;
+
+ md = RTE_MBUF_DYNFIELD(tx_pkt, ipsec_pkt_md_offset, struct sxe2_ipsec_pkt_metadata *);
+ *ipsec_offset = md->esp_head_offset;
+ *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_EN;
+ if (md->mode == SXE2_IPSEC_MODE_ONLY_ENCRYPT)
+ *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_MODE;
+
+ if (md->algo == SXE2_IPSEC_ALGO_SM4_CBC_AND_SM3_96_HMAC)
+ *desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_IPSEC_ENGINE;
+
+ *desc_type_cmd_tso_mss |= (uint64_t)(md->sa_idx) << SXE2_TX_CTXT_DESC_IPSEC_SA_SHIFT;
+}
+
static __rte_always_inline uint64_t
sxe2_tx_data_desc_build_cobt(uint32_t cmd, uint32_t offset, uint16_t buf_size, uint16_t l2tag)
{
@@ -426,6 +445,11 @@ uint16_t sxe2_tx_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt
else if (offloads & RTE_MBUF_F_TX_IEEE1588_TMST)
desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_CMD_TSYN_MASK;
+ if (offloads & RTE_MBUF_F_TX_SEC_OFFLOAD) {
+ sxe2_desc_ipsec_fill(tx_pkt, txq, &ipsec_offset,
+ &desc_type_cmd_tso_mss);
+ }
+
if (offloads & RTE_MBUF_F_TX_QINQ) {
desc_l2tag2 = tx_pkt->vlan_tci_outer;
desc_type_cmd_tso_mss |= SXE2_TX_CTXT_DESC_CMD_IL2TAG2_MASK;
@@ -786,6 +810,36 @@ static inline void sxe2_rx_desc_ptp_para_fill(struct sxe2_rx_queue *rxq,
rxq->ts_low);
}
}
+
+static inline void sxe2_rx_desc_ipsec_para_fill(struct sxe2_rx_queue *rxq __rte_unused,
+ struct rte_mbuf *mbuf, union sxe2_rx_desc *desc)
+{
+ uint32_t status_lrocnt_fdpf_id = rte_le_to_cpu_32(desc->wb.status_lrocnt_fdpf_id);
+ enum sxe2_rx_desc_ipsec_status ipsec_status;
+
+ if (status_lrocnt_fdpf_id & SXE2_RX_DESC_IPSEC_PKT_MASK) {
+ mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD;
+ ipsec_status = SXE2_RX_DESC_IPSEC_STATUS_VAL_GET(status_lrocnt_fdpf_id);
+ switch (ipsec_status) {
+ case SXE2_RX_DESC_IPSEC_STATUS_SUCCESS:
+ break;
+ case SXE2_RX_DESC_IPSEC_STATUS_PKG_OVER_2K:
+ case SXE2_RX_DESC_IPSEC_STATUS_SPI_IP_INVALID:
+ case SXE2_RX_DESC_IPSEC_STATUS_SA_INVALID:
+ case SXE2_RX_DESC_IPSEC_STATUS_NOT_ALIGN:
+ case SXE2_RX_DESC_IPSEC_STATUS_ICV_ERROR:
+ case SXE2_RX_DESC_IPSEC_STATUS_BY_PASSH:
+ case SXE2_RX_DESC_IPSEC_STATUS_MAC_BY_PASSH:
+ PMD_LOG_INFO(RX, "IPsec status error:%d", ipsec_status);
+ mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
+ break;
+ default:
+ PMD_LOG_INFO(RX, "Invalid ipsec status:%d", ipsec_status);
+ mbuf->ol_flags |= RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED;
+ break;
+ }
+ }
+}
#endif
static __rte_always_inline void
@@ -803,6 +857,7 @@ sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, struct rte_mbuf *mbuf
sxe2_rx_desc_vlan_para_fill(mbuf, rxd);
sxe2_rx_desc_filter_para_fill(rxq, mbuf, rxd);
#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+ sxe2_rx_desc_ipsec_para_fill(rxq, mbuf, rxd);
sxe2_rx_desc_ptp_para_fill(rxq, mbuf, rxd);
#endif
--
2.52.0
^ permalink raw reply related
* [PATCH v14 10/20] net/sxe2: add NEON vec Rx/Tx burst functions
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
- Implement sxe2_recv_pkts_vec_neon for bulk packet receiving.
- Implement sxe2_xmit_pkts_vec_neon for bulk packet transmission.
- Added logic to select the vectorized path based on runtime config
and CPU flags (RTE_ARCH_ARM64).
Vectorized path improves throughput for small packets by processing
multiple descriptors simultaneously using SIMD instructions.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 2 +
drivers/net/sxe2/sxe2_txrx.c | 39 +-
drivers/net/sxe2/sxe2_txrx_vec.h | 16 +-
drivers/net/sxe2/sxe2_txrx_vec_common.h | 1 +
drivers/net/sxe2/sxe2_txrx_vec_neon.c | 721 ++++++++++++++++++++++++
5 files changed, 774 insertions(+), 5 deletions(-)
create mode 100644 drivers/net/sxe2/sxe2_txrx_vec_neon.c
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index fc4466556b..4565046eae 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -48,6 +48,8 @@ if arch_subdir == 'x86'
include_directories: includes,
c_args: [cflags, '-mavx2'])
objs += sxe2_avx2_lib.extract_objects('sxe2_txrx_vec_avx2.c')
+elif arch_subdir == 'arm'
+ sources += files('sxe2_txrx_vec_neon.c')
endif
sources += files(
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index eaf95259a5..a919a84450 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -175,6 +175,9 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
if ((0 == (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK)))
tx_mode_flags |= SXE2_TX_MODE_VEC_SSE;
+#elif defined(RTE_ARCH_ARM64)
+ if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) == 1)
+ tx_mode_flags |= (vec_flags | SXE2_TX_MODE_VEC_NEON);
#endif
if (tx_mode_flags & SXE2_TX_MODE_VEC_SET_MASK) {
ret = sxe2_tx_queues_vec_prepare(dev);
@@ -218,8 +221,15 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
dev->tx_pkt_burst = sxe2_tx_pkts_vec_sse_simple;
}
}
- } else {
+#elif defined(RTE_ARCH_ARM64)
+ if (tx_mode_flags & SXE2_TX_MODE_VEC_NEON) {
+ dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
+ dev->tx_pkt_burst = sxe2_tx_pkts_vec_neon;
+ } else {
+ dev->tx_pkt_burst = sxe2_tx_pkts_vec_neon_simple;
+ }
#endif
+ } else {
if (tx_mode_flags & SXE2_TX_MODE_SIMPLE_BATCH) {
dev->tx_pkt_prepare = NULL;
dev->tx_pkt_burst = sxe2_tx_pkts_simple;
@@ -227,9 +237,7 @@ void sxe2_tx_mode_func_set(struct rte_eth_dev *dev)
dev->tx_pkt_prepare = sxe2_tx_pkts_prepare;
dev->tx_pkt_burst = sxe2_tx_pkts;
}
-#ifdef RTE_ARCH_X86
}
-#endif
}
static const struct {
@@ -253,6 +261,12 @@ static const struct {
{ sxe2_tx_pkts_vec_sse_simple,
"Vector SSE Simple" },
#endif
+#ifdef RTE_ARCH_ARM64
+ { sxe2_tx_pkts_vec_neon,
+ "Vector NEON" },
+ { sxe2_tx_pkts_vec_neon_simple,
+ "Vector NEON Simple" },
+#endif
};
int32_t sxe2_tx_burst_mode_get(struct rte_eth_dev *dev,
@@ -356,6 +370,11 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
if (((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) == 0) &&
rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128)
rx_mode_flags |= SXE2_RX_MODE_VEC_SSE;
+
+#elif defined(RTE_ARCH_ARM64)
+ if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_NEON) == 1) {
+ rx_mode_flags |= (vec_flags | SXE2_RX_MODE_VEC_NEON);
+ }
#endif
if ((rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) != 0) {
ret = sxe2_rx_queues_vec_prepare(dev);
@@ -387,6 +406,14 @@ void sxe2_rx_mode_func_set(struct rte_eth_dev *dev)
}
return;
}
+#elif defined(RTE_ARCH_ARM64)
+ if (rx_mode_flags & SXE2_RX_MODE_VEC_SET_MASK) {
+ if (rx_mode_flags & SXE2_RX_MODE_VEC_OFFLOAD)
+ dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_neon_offload;
+ else
+ dev->rx_pkt_burst = sxe2_rx_pkts_scattered_vec_neon;
+ return;
+ }
#endif
if (sxe2_rx_offload_en_check(dev, RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT))
dev->rx_pkt_burst = sxe2_rx_pkts_scattered_split;
@@ -416,6 +443,12 @@ static const struct {
{ sxe2_rx_pkts_scattered_vec_sse_offload,
"Vector SSE Scattered" },
#endif
+#ifdef RTE_ARCH_ARM64
+ { sxe2_rx_pkts_scattered_vec_neon,
+ "Vector NEON Scattered" },
+ { sxe2_rx_pkts_scattered_vec_neon_offload,
+ "Offload Vector NEON Scattered" },
+#endif
};
int32_t sxe2_rx_burst_mode_get(struct rte_eth_dev *dev,
diff --git a/drivers/net/sxe2/sxe2_txrx_vec.h b/drivers/net/sxe2/sxe2_txrx_vec.h
index 369777606f..c139aed776 100644
--- a/drivers/net/sxe2/sxe2_txrx_vec.h
+++ b/drivers/net/sxe2/sxe2_txrx_vec.h
@@ -13,19 +13,23 @@
#define SXE2_RX_MODE_VEC_SSE RTE_BIT32(2)
#define SXE2_RX_MODE_VEC_AVX2 RTE_BIT32(3)
#define SXE2_RX_MODE_VEC_AVX512 RTE_BIT32(4)
+#define SXE2_RX_MODE_VEC_NEON RTE_BIT32(5)
#define SXE2_RX_MODE_BATCH_ALLOC RTE_BIT32(10)
#define SXE2_RX_MODE_VEC_SET_MASK (SXE2_RX_MODE_VEC_SIMPLE | \
SXE2_RX_MODE_VEC_OFFLOAD | SXE2_RX_MODE_VEC_SSE | \
- SXE2_RX_MODE_VEC_AVX2 | SXE2_RX_MODE_VEC_AVX512)
+ SXE2_RX_MODE_VEC_AVX2 | SXE2_RX_MODE_VEC_AVX512 | \
+ SXE2_RX_MODE_VEC_NEON)
#define SXE2_TX_MODE_VEC_SIMPLE RTE_BIT32(0)
#define SXE2_TX_MODE_VEC_OFFLOAD RTE_BIT32(1)
#define SXE2_TX_MODE_VEC_SSE RTE_BIT32(2)
#define SXE2_TX_MODE_VEC_AVX2 RTE_BIT32(3)
#define SXE2_TX_MODE_VEC_AVX512 RTE_BIT32(4)
+#define SXE2_TX_MODE_VEC_NEON RTE_BIT32(5)
#define SXE2_TX_MODE_SIMPLE_BATCH RTE_BIT32(10)
#define SXE2_TX_MODE_VEC_SET_MASK (SXE2_TX_MODE_VEC_SIMPLE | \
SXE2_TX_MODE_VEC_OFFLOAD | SXE2_TX_MODE_VEC_SSE | \
- SXE2_TX_MODE_VEC_AVX2 | SXE2_TX_MODE_VEC_AVX512)
+ SXE2_TX_MODE_VEC_AVX2 | SXE2_TX_MODE_VEC_AVX512 | \
+ SXE2_TX_MODE_VEC_NEON)
#define SXE2_TX_VEC_NO_SUPPORT_OFFLOAD ( \
RTE_ETH_TX_OFFLOAD_MULTI_SEGS | \
RTE_ETH_TX_OFFLOAD_QINQ_INSERT | \
@@ -76,6 +80,14 @@ uint16_t sxe2_rx_pkts_scattered_vec_avx2(void *rx_queue,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
uint16_t sxe2_rx_pkts_scattered_vec_avx2_offload(void *rx_queue,
struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
+
+#elif defined(RTE_ARCH_ARM64)
+uint16_t sxe2_rx_pkts_scattered_vec_neon(void *rx_queue, struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts);
+uint16_t sxe2_rx_pkts_scattered_vec_neon_offload(void *rx_queue, struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_neon_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
+uint16_t sxe2_tx_pkts_vec_neon(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts);
#endif
int32_t __rte_cold sxe2_tx_vec_support_check(struct rte_eth_dev *dev, uint32_t *vec_flags);
int32_t __rte_cold sxe2_tx_queues_vec_prepare(struct rte_eth_dev *dev);
diff --git a/drivers/net/sxe2/sxe2_txrx_vec_common.h b/drivers/net/sxe2/sxe2_txrx_vec_common.h
index 6b1649c390..c093c3c80c 100644
--- a/drivers/net/sxe2/sxe2_txrx_vec_common.h
+++ b/drivers/net/sxe2/sxe2_txrx_vec_common.h
@@ -2,6 +2,7 @@
* Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
*/
+
#ifndef SXE2_TXRX_VEC_COMMON_H
#define SXE2_TXRX_VEC_COMMON_H
diff --git a/drivers/net/sxe2/sxe2_txrx_vec_neon.c b/drivers/net/sxe2/sxe2_txrx_vec_neon.c
new file mode 100644
index 0000000000..26d3bef21a
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_vec_neon.c
@@ -0,0 +1,721 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifdef RTE_ARCH_ARM64
+#include <arm_neon.h>
+#include <rte_vect.h>
+
+#include "sxe2_txrx_vec_common.h"
+#include "sxe2_txrx_vec.h"
+#include "sxe2_common_log.h"
+
+#define PKTLEN_SHIFT 10
+#define SXE2_UINT16_BIT (CHAR_BIT * sizeof(uint16_t))
+
+static __rte_always_inline void
+sxe2_tx_desc_fill_one_neon(volatile union sxe2_tx_data_desc *desc,
+ struct rte_mbuf *pkt, uint64_t desc_cmd, bool with_offloads)
+{
+ uint64_t desc_qw1;
+ uint32_t desc_offset;
+
+ desc_qw1 = (SXE2_TX_DESC_DTYPE_DATA |
+ ((uint64_t)desc_cmd) << SXE2_TX_DATA_DESC_CMD_SHIFT |
+ ((uint64_t)pkt->data_len) << SXE2_TX_DATA_DESC_BUF_SZ_SHIFT);
+
+ desc_offset = SXE2_TX_DATA_DESC_MACLEN_VAL(pkt->l2_len);
+ desc_qw1 |= ((uint64_t)desc_offset) << SXE2_TX_DATA_DESC_OFFSET_SHIFT;
+ if (with_offloads)
+ sxe2_tx_desc_fill_offloads(pkt, &desc_qw1);
+
+ uint64x2_t data_desc = { rte_pktmbuf_iova(pkt), desc_qw1 };
+
+ vst1q_u64(RTE_CAST_PTR(uint64_t *, desc), data_desc);
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_neon_batch(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool with_offloads)
+{
+ volatile union sxe2_tx_data_desc *desc;
+ struct sxe2_tx_buffer *buffer;
+ uint16_t next_use;
+ uint16_t res_num;
+ uint16_t tx_num;
+ uint16_t i;
+
+ if (txq->desc_free_num < txq->free_thresh)
+ (void)sxe2_tx_bufs_free_vec(txq);
+
+ nb_pkts = RTE_MIN(txq->desc_free_num, nb_pkts);
+ if (unlikely(nb_pkts == 0)) {
+ PMD_LOG_DEBUG(TX, "Tx pkts neon batch: may not enough free desc, "
+ "free_desc=%u, need_tx_pkts=%u",
+ txq->desc_free_num, nb_pkts);
+ goto l_end;
+ }
+ tx_num = nb_pkts;
+
+ next_use = txq->next_use;
+ desc = &txq->desc_ring[next_use];
+ buffer = &txq->buffer_ring[next_use];
+
+ txq->desc_free_num -= nb_pkts;
+
+ res_num = txq->ring_depth - txq->next_use;
+
+ if (tx_num >= res_num) {
+ sxe2_tx_pkts_mbuf_fill(buffer, tx_pkts, res_num);
+
+ for (i = 0; i < res_num - 1; ++i, ++tx_pkts, ++desc) {
+ sxe2_tx_desc_fill_one_neon(desc, *tx_pkts,
+ SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+ }
+
+ sxe2_tx_desc_fill_one_neon(desc, *tx_pkts++,
+ (SXE2_TX_DATA_DESC_CMD_EOP | SXE2_TX_DATA_DESC_CMD_RS),
+ with_offloads);
+
+ tx_num -= res_num;
+
+ next_use = 0;
+ txq->next_rs = txq->rs_thresh - 1;
+ desc = &txq->desc_ring[next_use];
+ buffer = &txq->buffer_ring[next_use];
+ }
+
+ sxe2_tx_pkts_mbuf_fill(buffer, tx_pkts, tx_num);
+
+ for (i = 0; i < tx_num; ++i, ++tx_pkts, ++desc) {
+ sxe2_tx_desc_fill_one_neon(desc, *tx_pkts,
+ SXE2_TX_DATA_DESC_CMD_EOP, with_offloads);
+ }
+
+ next_use += tx_num;
+ if (next_use > txq->next_rs) {
+ txq->desc_ring[txq->next_rs].read.type_cmd_off_bsz_l2t |=
+ rte_cpu_to_le_64(SXE2_TX_DATA_DESC_CMD_RS_MASK);
+
+ txq->next_rs += txq->rs_thresh;
+ }
+ txq->next_use = next_use;
+
+ SXE2_PCI_REG_WRITE_WC(txq->tdt_reg_addr, txq->next_use);
+
+l_end:
+ return nb_pkts;
+}
+
+static __rte_always_inline uint16_t
+sxe2_tx_pkts_vec_neon_common(struct sxe2_tx_queue *txq, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool with_offloads)
+{
+ uint16_t tx_done_num = 0;
+ uint16_t tx_once_num;
+ uint16_t tx_need_num;
+
+ while (nb_pkts) {
+ tx_need_num = RTE_MIN(nb_pkts, txq->rs_thresh);
+ tx_once_num = sxe2_tx_pkts_vec_neon_batch(txq,
+ tx_pkts + tx_done_num,
+ tx_need_num, with_offloads);
+
+ nb_pkts -= tx_once_num;
+ tx_done_num += tx_once_num;
+
+ if (tx_once_num < tx_need_num)
+ break;
+ }
+
+ PMD_LOG_DEBUG(TX, "Tx pkts neon: port_id=%u, queue_id=%u, "
+ "nb_pkts=%u, tx_done_num=%u with_offloads=%u",
+ txq->port_id, txq->idx_in_func, nb_pkts, tx_done_num, with_offloads);
+
+ return tx_done_num;
+}
+
+uint16_t sxe2_tx_pkts_vec_neon_simple(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return sxe2_tx_pkts_vec_neon_common((struct sxe2_tx_queue *)tx_queue,
+ tx_pkts, nb_pkts, false);
+}
+
+uint16_t sxe2_tx_pkts_vec_neon(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return sxe2_tx_pkts_vec_neon_common((struct sxe2_tx_queue *)tx_queue,
+ tx_pkts, nb_pkts, true);
+}
+
+static __rte_always_inline void
+sxe2_rx_desc_ptype_fill_neon(uint16x8_t staterr, struct rte_mbuf **__rte_restrict rx_pkts,
+ const uint32_t *__rte_restrict ptype_tbl)
+{
+ uint16x8_t ptype_mask = {
+ 0, 0x3FFULL,
+ 0, 0x3FFULL,
+ 0, 0x3FFULL,
+ 0, 0x3FFULL,
+ };
+ uint16x8_t ptype_all;
+
+ ptype_all = vandq_u16(staterr, ptype_mask);
+
+ rx_pkts[3]->packet_type = ptype_tbl[vgetq_lane_u16(ptype_all, 3)];
+ rx_pkts[2]->packet_type = ptype_tbl[vgetq_lane_u16(ptype_all, 7)];
+ rx_pkts[1]->packet_type = ptype_tbl[vgetq_lane_u16(ptype_all, 1)];
+ rx_pkts[0]->packet_type = ptype_tbl[vgetq_lane_u16(ptype_all, 5)];
+}
+
+static __rte_always_inline uint32x4_t
+sxe2_rx_desc_fnav_flags_neon(uint64x2_t descs_arr[4])
+{
+ uint32x4_t descs_tmp1, descs_tmp2;
+ uint32x4_t descs_fnav_vld;
+ uint32x4_t v_zeros, v_ffff, v_u32_one;
+ uint32x4_t m_flags;
+
+ const uint32x4_t fdir_flags = vdupq_n_u32(RTE_MBUF_F_RX_FDIR |
+ RTE_MBUF_F_RX_FDIR_ID);
+
+ uint32x4_t d0 = vreinterpretq_u32_u64(descs_arr[0]);
+ uint32x4_t d1 = vreinterpretq_u32_u64(descs_arr[1]);
+ uint32x4_t d2 = vreinterpretq_u32_u64(descs_arr[2]);
+ uint32x4_t d3 = vreinterpretq_u32_u64(descs_arr[3]);
+
+ descs_tmp1 = vzip1q_u32(d1, d0);
+ descs_tmp2 = vzip1q_u32(d3, d2);
+
+ uint64x2_t a = vreinterpretq_u64_u32(descs_tmp1);
+ uint64x2_t b = vreinterpretq_u64_u32(descs_tmp2);
+
+ descs_fnav_vld = vreinterpretq_u32_u64(vcombine_u64(vget_low_u64(a), vget_low_u64(b)));
+
+ descs_fnav_vld = vshlq_n_u32(descs_fnav_vld, 26);
+ descs_fnav_vld = vshrq_n_u32(descs_fnav_vld, 31);
+
+ v_zeros = vdupq_n_u32(0);
+ v_ffff = vceqq_u32(v_zeros, v_zeros);
+ v_u32_one = vshrq_n_u32(v_ffff, 31);
+
+ m_flags = vceqq_u32(descs_fnav_vld, v_u32_one);
+
+ m_flags = vandq_u32(m_flags, fdir_flags);
+ return m_flags;
+}
+
+static __rte_always_inline void
+sxe2_rx_desc_offloads_para_fill_neon(struct sxe2_rx_queue *rxq,
+ volatile union sxe2_rx_desc *desc,
+ uint64x2_t descs[4], struct rte_mbuf **rx_pkts)
+{
+ uint32x4_t desc_lo, desc_hi, flags, tmp_flags;
+ const uint64x2_t mbuf_init = {rxq->mbuf_init_value, 0};
+ uint64x2_t rearm0, rearm1, rearm2, rearm3;
+
+ const uint32x4_t desc_msk = {
+ 0x00001C04, 0x00001C04, 0x00001C04, 0x00001C04};
+
+ const uint32x4_t rss_msk = {
+ 0x20000000, 0x20000000, 0x20000000, 0x20000000};
+
+ const uint32x4_t vlan_msk = {
+ RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED,
+ RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED,
+ RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED,
+ RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED
+ };
+ const uint8x16_t vlan_flags = {
+ 0, 0, 0, 0,
+ RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ const uint8x16_t rss_flags = {
+ 0, 0, 0, 0,
+ RTE_MBUF_F_RX_RSS_HASH, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ const uint32x4_t cksum_mask = {
+ RTE_MBUF_F_RX_IP_CKSUM_MASK | RTE_MBUF_F_RX_L4_CKSUM_MASK |
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK | RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD,
+ RTE_MBUF_F_RX_IP_CKSUM_MASK | RTE_MBUF_F_RX_L4_CKSUM_MASK |
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK | RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD,
+ RTE_MBUF_F_RX_IP_CKSUM_MASK | RTE_MBUF_F_RX_L4_CKSUM_MASK |
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK | RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD,
+ RTE_MBUF_F_RX_IP_CKSUM_MASK | RTE_MBUF_F_RX_L4_CKSUM_MASK |
+ RTE_MBUF_F_RX_OUTER_L4_CKSUM_MASK | RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD,
+ };
+
+ const uint8x16_t cksum_flags = {
+ ((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+ ((RTE_MBUF_F_RX_L4_CKSUM_GOOD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+ ((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+ ((RTE_MBUF_F_RX_L4_CKSUM_BAD | RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+ ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+ RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+ ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_GOOD |
+ RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+ ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+ RTE_MBUF_F_RX_IP_CKSUM_GOOD) >> 1),
+ ((RTE_MBUF_F_RX_OUTER_IP_CKSUM_BAD | RTE_MBUF_F_RX_L4_CKSUM_BAD |
+ RTE_MBUF_F_RX_IP_CKSUM_BAD) >> 1),
+ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ {
+ uint32x4_t d0 = vreinterpretq_u32_u64(descs[0]);
+ uint32x4_t d1 = vreinterpretq_u32_u64(descs[1]);
+ uint32x4_t d2 = vreinterpretq_u32_u64(descs[2]);
+ uint32x4_t d3 = vreinterpretq_u32_u64(descs[3]);
+ uint64x2_t f64, t64;
+
+ flags = vzip2q_u32(d1, d0);
+ tmp_flags = vzip2q_u32(d3, d2);
+ f64 = vreinterpretq_u64_u32(flags);
+ t64 = vreinterpretq_u64_u32(tmp_flags);
+ desc_lo = vreinterpretq_u32_u64(vcombine_u64(vget_low_u64(f64),
+ vget_low_u64(t64)));
+ desc_hi = vreinterpretq_u32_u64(vcombine_u64(vget_high_u64(f64),
+ vget_high_u64(t64)));
+ }
+
+ desc_lo = vandq_u32(desc_lo, desc_msk);
+ desc_hi = vandq_u32(desc_hi, rss_msk);
+
+ tmp_flags = vreinterpretq_u32_u8(vqtbl1q_u8(vlan_flags,
+ vreinterpretq_u8_u32(desc_lo)));
+ flags = vandq_u32(tmp_flags, vlan_msk);
+
+ desc_lo = vshrq_n_u32(desc_lo, 10);
+ tmp_flags = vreinterpretq_u32_u8(vqtbl1q_u8(cksum_flags,
+ vreinterpretq_u8_u32(desc_lo)));
+ tmp_flags = vshlq_n_u32(tmp_flags, 1);
+ tmp_flags = vandq_u32(tmp_flags, cksum_mask);
+ flags = vorrq_u32(flags, tmp_flags);
+
+ desc_hi = vshrq_n_u32(desc_hi, 27);
+ tmp_flags = vreinterpretq_u32_u8(vqtbl1q_u8(rss_flags,
+ vreinterpretq_u8_u32(desc_hi)));
+ flags = vorrq_u32(flags, tmp_flags);
+
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+ if (rxq->fnav_enable) {
+ uint32x4_t tmp_fnav_flags = sxe2_rx_desc_fnav_flags_neon(descs);
+ flags = vorrq_u32(flags, tmp_fnav_flags);
+
+ rx_pkts[0]->hash.fdir.hi = desc[0].wb.fd_filter_id;
+ rx_pkts[1]->hash.fdir.hi = desc[1].wb.fd_filter_id;
+ rx_pkts[2]->hash.fdir.hi = desc[2].wb.fd_filter_id;
+ rx_pkts[3]->hash.fdir.hi = desc[3].wb.fd_filter_id;
+ }
+#endif
+
+ rearm0 = vsetq_lane_u64(vgetq_lane_u32(flags, 0), mbuf_init, 1);
+ rearm1 = vsetq_lane_u64(vgetq_lane_u32(flags, 1), mbuf_init, 1);
+ rearm2 = vsetq_lane_u64(vgetq_lane_u32(flags, 2), mbuf_init, 1);
+ rearm3 = vsetq_lane_u64(vgetq_lane_u32(flags, 3), mbuf_init, 1);
+
+ vst1q_u64((uint64_t *)&rx_pkts[0]->rearm_data, rearm0);
+ vst1q_u64((uint64_t *)&rx_pkts[1]->rearm_data, rearm1);
+ vst1q_u64((uint64_t *)&rx_pkts[2]->rearm_data, rearm2);
+ vst1q_u64((uint64_t *)&rx_pkts[3]->rearm_data, rearm3);
+}
+
+static inline void sxe2_rx_queue_rearm_neon(struct sxe2_rx_queue *rxq)
+{
+ volatile union sxe2_rx_desc *desc;
+ struct rte_mbuf **buffer;
+ struct rte_mbuf *mbuf0, *mbuf1;
+ uint64x2_t dma_addr0, dma_addr1;
+ uint64x2_t zero = vdupq_n_u64(0);
+ uint64x2_t virt_addr0, virt_addr1;
+ uint64x2_t hdr_room = vdupq_n_u64(RTE_PKTMBUF_HEADROOM);
+ int32_t ret;
+ uint16_t i;
+ uint16_t new_tail;
+
+ buffer = &rxq->buffer_ring[rxq->realloc_start];
+ desc = &rxq->desc_ring[rxq->realloc_start];
+
+ ret = rte_mempool_get_bulk(rxq->mb_pool, (void *)buffer,
+ SXE2_RX_REARM_THRESH_VEC);
+ if (ret != 0) {
+ PMD_LOG_INFO(RX, "Rx mbuf vec alloc failed port_id=%u "
+ "queue_id=%u", rxq->port_id, rxq->idx_in_func);
+
+ if ((rxq->realloc_num + SXE2_RX_REARM_THRESH_VEC) >= rxq->ring_depth) {
+ for (i = 0; i < SXE2_RX_NUM_PER_LOOP_NEON; ++i) {
+ buffer[i] = &rxq->fake_mbuf;
+ vst1q_u64(RTE_CAST_PTR(uint64_t *, &desc[i].read), zero);
+ }
+ }
+
+ rxq->vsi->adapter->dev_info.dev_data->rx_mbuf_alloc_failed +=
+ SXE2_RX_REARM_THRESH_VEC;
+ goto l_end;
+ }
+
+ for (i = 0; i < SXE2_RX_REARM_THRESH_VEC; i += 2, buffer += 2) {
+ mbuf0 = buffer[0];
+ mbuf1 = buffer[1];
+#if RTE_IOVA_IN_MBUF
+ RTE_BUILD_BUG_ON(offsetof(struct rte_mbuf, buf_iova) !=
+ offsetof(struct rte_mbuf, buf_addr) + 8);
+#endif
+ virt_addr0 = vld1q_u64((uint64_t *)&mbuf0->buf_addr);
+ virt_addr1 = vld1q_u64((uint64_t *)&mbuf1->buf_addr);
+
+#if RTE_IOVA_IN_MBUF
+ dma_addr0 = vdupq_n_u64((uint64_t)vget_high_u64(virt_addr0));
+ dma_addr1 = vdupq_n_u64((uint64_t)vget_high_u64(virt_addr1));
+#else
+ dma_addr0 = vdupq_n_u64((uint64_t)vget_low_u64(virt_addr0));
+ dma_addr1 = vdupq_n_u64((uint64_t)vget_low_u64(virt_addr1));
+#endif
+ dma_addr0 = vaddq_u64(dma_addr0, hdr_room);
+ dma_addr1 = vaddq_u64(dma_addr1, hdr_room);
+
+ vst1q_u64(RTE_CAST_PTR(uint64_t *, &desc++->read), dma_addr0);
+ vst1q_u64(RTE_CAST_PTR(uint64_t *, &desc++->read), dma_addr1);
+ }
+
+ rxq->realloc_start += SXE2_RX_REARM_THRESH_VEC;
+ if (rxq->realloc_start >= rxq->ring_depth)
+ rxq->realloc_start = 0;
+ rxq->realloc_num -= SXE2_RX_REARM_THRESH_VEC;
+
+ new_tail = (rxq->realloc_start == 0) ?
+ (rxq->ring_depth - 1) : (rxq->realloc_start - 1);
+
+ SXE2_PCI_REG_WRITE_WC(rxq->rdt_reg_addr, new_tail);
+
+l_end:
+ return;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_common_vec_neon(struct sxe2_rx_queue *rxq, struct rte_mbuf **rx_pkts,
+ uint16_t nb_pkts, uint8_t *split_rxe_flags, uint8_t *umbcast_flags,
+ bool do_offload)
+{
+ volatile union sxe2_rx_desc *desc;
+ struct rte_mbuf **buffer;
+ uint32_t i;
+ uint16_t done_num = 0;
+ const uint32_t *ptype_tbl = rxq->vsi->adapter->ptype_tbl;
+
+ uint8x16_t rvp_shuf_mask = {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 12, 13, 0xFF, 0xFF,
+ 12, 13,
+ 2, 3,
+ 4, 5, 6, 7
+ };
+
+ uint16x8_t crc_adjust = {
+ 0, 0,
+ rxq->crc_len,
+ 0, rxq->crc_len,
+ 0, 0, 0
+ };
+
+ desc = &rxq->desc_ring[rxq->processing_idx];
+ rte_prefetch0(desc);
+
+ nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, SXE2_RX_NUM_PER_LOOP_NEON);
+
+ if (rxq->realloc_num > SXE2_RX_REARM_THRESH_VEC)
+ sxe2_rx_queue_rearm_neon(rxq);
+
+ if ((rte_le_to_cpu_64(desc->wb.status_err_ptype_len) &
+ SXE2_RX_DESC_STATUS_DD_MASK) == 0) {
+ goto l_end;
+ }
+
+ buffer = &rxq->buffer_ring[rxq->processing_idx];
+ for (i = 0; i < nb_pkts; i += SXE2_RX_NUM_PER_LOOP_NEON,
+ desc += SXE2_RX_NUM_PER_LOOP_NEON) {
+ uint64x2_t descs[SXE2_RX_NUM_PER_LOOP_NEON];
+ uint8x16_t pkt_mb1, pkt_mb2, pkt_mb3, pkt_mb4;
+ uint64x2_t mbp1, mbp2;
+ uint16x8_t staterr;
+ uint16x8_t tmp;
+ uint16_t bit_num;
+
+ descs[3] = vld1q_u64(RTE_CAST_PTR(uint64_t *, desc + 3));
+ rte_atomic_thread_fence(rte_memory_order_acquire);
+ descs[2] = vld1q_u64(RTE_CAST_PTR(uint64_t *, desc + 2));
+ rte_atomic_thread_fence(rte_memory_order_acquire);
+ descs[1] = vld1q_u64(RTE_CAST_PTR(uint64_t *, desc + 1));
+ rte_atomic_thread_fence(rte_memory_order_acquire);
+ descs[0] = vld1q_u64(RTE_CAST_PTR(uint64_t *, desc));
+
+ rte_atomic_thread_fence(rte_memory_order_acquire);
+
+ descs[3] = vld1q_lane_u64(RTE_CAST_PTR(uint64_t *, desc + 3), descs[3], 0);
+ descs[2] = vld1q_lane_u64(RTE_CAST_PTR(uint64_t *, desc + 2), descs[2], 0);
+ descs[1] = vld1q_lane_u64(RTE_CAST_PTR(uint64_t *, desc + 1), descs[1], 0);
+ descs[0] = vld1q_lane_u64(RTE_CAST_PTR(uint64_t *, desc), descs[0], 0);
+
+ mbp1 = vld1q_u64((uint64_t *)&buffer[i]);
+ mbp2 = vld1q_u64((uint64_t *)&buffer[i + 2]);
+
+ vst1q_u64((uint64_t *)&rx_pkts[i], mbp1);
+ vst1q_u64((uint64_t *)&rx_pkts[i + 2], mbp2);
+
+ if (split_rxe_flags) {
+ rte_mbuf_prefetch_part2(rx_pkts[i]);
+ rte_mbuf_prefetch_part2(rx_pkts[i + 1]);
+ rte_mbuf_prefetch_part2(rx_pkts[i + 2]);
+ rte_mbuf_prefetch_part2(rx_pkts[i + 3]);
+ }
+
+ pkt_mb4 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[3]), rvp_shuf_mask);
+ pkt_mb3 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[2]), rvp_shuf_mask);
+ pkt_mb2 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[1]), rvp_shuf_mask);
+ pkt_mb1 = vqtbl1q_u8(vreinterpretq_u8_u64(descs[0]), rvp_shuf_mask);
+
+ if (do_offload) {
+ sxe2_rx_desc_offloads_para_fill_neon(rxq, desc, descs, &rx_pkts[i]);
+ } else {
+ const uint64x2_t mbuf_init = {
+ rxq->mbuf_init_value,
+ 0,
+ };
+
+ vst1q_u64((uint64_t *)&rx_pkts[i]->rearm_data, mbuf_init);
+ vst1q_u64((uint64_t *)&rx_pkts[i + 1]->rearm_data, mbuf_init);
+ vst1q_u64((uint64_t *)&rx_pkts[i + 2]->rearm_data, mbuf_init);
+ vst1q_u64((uint64_t *)&rx_pkts[i + 3]->rearm_data, mbuf_init);
+ }
+
+ tmp = vsubq_u16(vreinterpretq_u16_u8(pkt_mb4), crc_adjust);
+ pkt_mb4 = vreinterpretq_u8_u16(tmp);
+ tmp = vsubq_u16(vreinterpretq_u16_u8(pkt_mb3), crc_adjust);
+ pkt_mb3 = vreinterpretq_u8_u16(tmp);
+ tmp = vsubq_u16(vreinterpretq_u16_u8(pkt_mb2), crc_adjust);
+ pkt_mb2 = vreinterpretq_u8_u16(tmp);
+ tmp = vsubq_u16(vreinterpretq_u16_u8(pkt_mb1), crc_adjust);
+ pkt_mb1 = vreinterpretq_u8_u16(tmp);
+
+ vst1q_u8((void *)&rx_pkts[i + 3]->rx_descriptor_fields1,
+ pkt_mb4);
+ vst1q_u8((void *)&rx_pkts[i + 2]->rx_descriptor_fields1,
+ pkt_mb3);
+ vst1q_u8((void *)&rx_pkts[i + 1]->rx_descriptor_fields1,
+ pkt_mb2);
+ vst1q_u8((void *)&rx_pkts[i]->rx_descriptor_fields1,
+ pkt_mb1);
+
+ if (likely(i + SXE2_RX_NUM_PER_LOOP_NEON < nb_pkts))
+ rte_prefetch_non_temporal(desc + SXE2_RX_NUM_PER_LOOP_NEON);
+
+ {
+ uint32x4_t d0 = vreinterpretq_u32_u64(descs[0]);
+ uint32x4_t d1 = vreinterpretq_u32_u64(descs[1]);
+ uint32x4_t d2 = vreinterpretq_u32_u64(descs[2]);
+ uint32x4_t d3 = vreinterpretq_u32_u64(descs[3]);
+ uint32x4_t sterr_tmp1 = vzip2q_u32(d1, d0);
+ uint32x4_t sterr_tmp2 = vzip2q_u32(d3, d2);
+ uint32x4_t sterr_u32 = vzip1q_u32(sterr_tmp1, sterr_tmp2);
+
+ staterr = vreinterpretq_u16_u32(sterr_u32);
+ }
+
+ sxe2_rx_desc_ptype_fill_neon(staterr, &rx_pkts[i], ptype_tbl);
+
+ if (umbcast_flags != NULL) {
+ uint32x4_t umbcast_mask = {
+ SXE2_RX_DESC_STATUS_UMBCAST_MASK, SXE2_RX_DESC_STATUS_UMBCAST_MASK,
+ SXE2_RX_DESC_STATUS_UMBCAST_MASK, SXE2_RX_DESC_STATUS_UMBCAST_MASK,
+ };
+
+ uint8x16_t umbcast_shuf_mask = {
+ 0x0B, 0x03, 0x0F, 0x07,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ };
+ uint8x16_t umbcast_bits =
+ vreinterpretq_u8_u32(vandq_u32(vreinterpretq_u32_u16(staterr),
+ umbcast_mask));
+
+ umbcast_bits = vqtbl1q_u8(umbcast_bits, umbcast_shuf_mask);
+ vst1q_lane_u32((uint32_t *)umbcast_flags,
+ vreinterpretq_u32_u8(umbcast_bits), 0);
+ umbcast_flags += SXE2_RX_NUM_PER_LOOP_NEON;
+ }
+
+ if (split_rxe_flags) {
+ uint8x16_t eop_shuf_mask = {
+ 0x08, 0x00, 0x0C, 0x04,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF};
+ uint8x16_t eop_bits;
+ uint32x4_t rxe_mask = {
+ 0x2080, 0x2080, 0x2080, 0x2080
+ };
+ uint32x4_t rxe_bits;
+ uint32x4_t eop_mask;
+
+ eop_mask = vshlq_n_u32(vdupq_n_u32(1), SXE2_RX_DESC_STATUS_EOP_SHIFT);
+ eop_bits = vandq_u8(vmvnq_u8(vreinterpretq_u8_u16(staterr)),
+ vreinterpretq_u8_u32(eop_mask));
+
+ rxe_bits = vandq_u32(vreinterpretq_u32_u16(staterr), rxe_mask);
+ rxe_bits = vshrq_n_u32(rxe_bits, 7);
+
+ eop_bits = vorrq_u8(eop_bits, vreinterpretq_u8_u32(rxe_bits));
+
+ eop_bits = vqtbl1q_u8(eop_bits, eop_shuf_mask);
+
+ vst1q_lane_u32((uint32_t *)split_rxe_flags,
+ vreinterpretq_u32_u8(eop_bits), 0);
+ split_rxe_flags += SXE2_RX_NUM_PER_LOOP_NEON;
+
+#ifdef RTE_IOVA_IN_MBUF
+ rx_pkts[i]->next = NULL;
+ rx_pkts[i + 1]->next = NULL;
+ rx_pkts[i + 2]->next = NULL;
+ rx_pkts[i + 3]->next = NULL;
+#endif
+ }
+
+ {
+ uint32x4_t dd_mask = vdupq_n_u32(1);
+ uint32x4_t sterr_dd = vandq_u32(vreinterpretq_u32_u16(staterr), dd_mask);
+ uint16x4_t packed_lo = vmovn_u32(sterr_dd);
+ uint64_t dd64 = vget_lane_u64(vreinterpret_u64_u16(packed_lo), 0);
+
+ bit_num = (uint16_t)rte_popcount64(dd64);
+ }
+ done_num += bit_num;
+ if (likely(bit_num != SXE2_RX_NUM_PER_LOOP_NEON))
+ break;
+ }
+
+ rxq->processing_idx += done_num;
+ rxq->processing_idx &= (rxq->ring_depth - 1);
+ rxq->realloc_num += done_num;
+
+l_end:
+ return done_num;
+}
+
+static __rte_always_inline uint16_t
+sxe2_rx_pkts_scattered_batch_vec_neon(struct sxe2_rx_queue *rxq,
+ struct rte_mbuf **rx_pkts, uint16_t nb_pkts, bool do_offload)
+{
+ const uint64_t *split_flags64;
+ uint8_t split_rxe_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+ uint8_t umbcast_flags[SXE2_RX_PKTS_BURST_BATCH_NUM_VEC] = {0};
+ uint16_t rx_done_num;
+ uint16_t rx_pkt_done_num;
+
+ rx_pkt_done_num = 0;
+
+ if (rxq->vsi->adapter->devargs.sw_stats_en) {
+ rx_done_num = sxe2_rx_pkts_common_vec_neon((struct sxe2_rx_queue *)rxq,
+ rx_pkts, nb_pkts, split_rxe_flags, umbcast_flags,
+ do_offload);
+ } else {
+ rx_done_num = sxe2_rx_pkts_common_vec_neon((struct sxe2_rx_queue *)rxq,
+ rx_pkts, nb_pkts, split_rxe_flags, NULL,
+ do_offload);
+ }
+
+ if (rx_done_num == 0)
+ goto l_end;
+
+ if (!rxq->vsi->adapter->devargs.sw_stats_en) {
+ split_flags64 = (uint64_t *)split_rxe_flags;
+
+ if (rxq->pkt_first_seg == NULL &&
+ split_flags64[0] == 0 && split_flags64[1] == 0 &&
+ split_flags64[2] == 0 && split_flags64[3] == 0) {
+ rx_pkt_done_num = rx_done_num;
+ goto l_end;
+ }
+
+ if (rxq->pkt_first_seg == NULL) {
+ while (rx_pkt_done_num < rx_done_num &&
+ split_rxe_flags[rx_pkt_done_num] == 0) {
+ rx_pkt_done_num++;
+ }
+
+ if (rx_pkt_done_num == rx_done_num)
+ goto l_end;
+
+ rxq->pkt_first_seg = rx_pkts[rx_pkt_done_num];
+ }
+ }
+
+ rx_pkt_done_num += sxe2_rx_pkts_refactor(rxq, &rx_pkts[rx_pkt_done_num],
+ rx_done_num - rx_pkt_done_num, &split_rxe_flags[rx_pkt_done_num],
+ &umbcast_flags[rx_pkt_done_num]);
+
+l_end:
+ return rx_pkt_done_num;
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_neon_offload(void *rx_queue,
+ struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ uint16_t done_num = 0;
+ uint16_t once_num;
+
+ while (nb_pkts > SXE2_RX_PKTS_BURST_BATCH_NUM_VEC) {
+ once_num = sxe2_rx_pkts_scattered_batch_vec_neon((struct sxe2_rx_queue *)rx_queue,
+ rx_pkts + done_num,
+ SXE2_RX_PKTS_BURST_BATCH_NUM_VEC,
+ true);
+
+ done_num += once_num;
+ nb_pkts -= once_num;
+
+ if (once_num < SXE2_RX_PKTS_BURST_BATCH_NUM_VEC)
+ goto l_end;
+ }
+
+ done_num += sxe2_rx_pkts_scattered_batch_vec_neon((struct sxe2_rx_queue *)rx_queue,
+ rx_pkts + done_num,
+ nb_pkts,
+ true);
+l_end:
+ return done_num;
+}
+
+uint16_t sxe2_rx_pkts_scattered_vec_neon(void *rx_queue,
+ struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ uint16_t done_num = 0;
+ uint16_t once_num;
+
+ while (nb_pkts > SXE2_RX_PKTS_BURST_BATCH_NUM_VEC) {
+ once_num = sxe2_rx_pkts_scattered_batch_vec_neon((struct sxe2_rx_queue *)rx_queue,
+ rx_pkts + done_num,
+ SXE2_RX_PKTS_BURST_BATCH_NUM_VEC,
+ false);
+
+ done_num += once_num;
+ nb_pkts -= once_num;
+
+ if (once_num < SXE2_RX_PKTS_BURST_BATCH_NUM_VEC)
+ goto l_end;
+ }
+
+ done_num += sxe2_rx_pkts_scattered_batch_vec_neon((struct sxe2_rx_queue *)rx_queue,
+ rx_pkts + done_num,
+ nb_pkts,
+ false);
+l_end:
+ return done_num;
+}
+#endif
--
2.52.0
^ permalink raw reply related
* [PATCH v14 20/20] net/sxe2: update sxe2 feature matrix docs
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
Update the sxe2.ini feature sheet to accurately reflect the recently
implemented hardware capabilities in the sxe2 PMD.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
doc/guides/nics/features/sxe2.ini | 56 +++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
diff --git a/doc/guides/nics/features/sxe2.ini b/doc/guides/nics/features/sxe2.ini
index 09ba2f558c..3c1e6a8a39 100644
--- a/doc/guides/nics/features/sxe2.ini
+++ b/doc/guides/nics/features/sxe2.ini
@@ -7,17 +7,73 @@
; is selected.
;
[Features]
+Speed capabilities = Y
+Link status = Y
+Link status event = Y
+Rx interrupt = Y
Fast mbuf free = P
Free Tx mbuf on demand = Y
Burst mode info = Y
Queue start/stop = Y
+Power mgmt address monitor = Y
Buffer split on Rx = P
Scattered Rx = Y
+Traffic manager = Y
CRC offload = Y
+VLAN offload = Y
+QinQ offload = P
L3 checksum offload = Y
L4 checksum offload = Y
+Timestamp offload = P
+Inner L3 checksum = P
+Inner L4 checksum = P
Rx descriptor status = Y
Tx descriptor status = Y
+MTU update = Y
+TSO = P
+Promiscuous mode = Y
+Allmulticast mode = Y
+Unicast MAC filter = Y
+RSS hash = Y
+RSS key update = Y
+RSS reta update = Y
+VLAN filter = Y
+Inline crypto = Y
+Packet type parsing = Y
+Timesync = Y
+Basic stats = Y
+Extended stats = Y
+FW version = Y
+Module EEPROM dump = Y
+Multiprocess aware = Y
Linux = Y
x86-32 = Y
x86-64 = Y
+
+[rte_flow items]
+eth = P
+geneve = Y
+gre = Y
+gtpu = Y
+ipv4 = Y
+ipv6 = Y
+ipv6_frag_ext = Y
+nvgre = Y
+sctp = Y
+tcp = Y
+udp = Y
+vlan = P
+vxlan = Y
+vxlan_gpe = Y
+
+[rte_flow actions]
+count = Y
+drop = Y
+mark = Y
+passthru = Y
+port_representor = Y
+queue = Y
+represented_port = Y
+rss = Y
+send_to_kernel = Y
+port_id = Y
--
2.52.0
^ permalink raw reply related
* [PATCH v14 17/20] net/sxe2: implement private dump info
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch implements the 'eth_dev_priv_dump' ops for the sxe2 PMD.
This interface allows applications to dump driver-specific internal
state and configuration information to a file stream.
The output includes:
- capabilities.
- device base info.
- device args info.
- device filter info.
- reprenstor info.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 1 +
drivers/net/sxe2/sxe2_dump.c | 289 ++++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_dump.h | 12 ++
drivers/net/sxe2/sxe2_ethdev.c | 3 +
drivers/net/sxe2/sxe2_ethdev_repr.c | 3 +
5 files changed, 308 insertions(+)
create mode 100644 drivers/net/sxe2/sxe2_dump.c
create mode 100644 drivers/net/sxe2/sxe2_dump.h
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index 65286299aa..d653d071a9 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -77,4 +77,5 @@ sources += files(
'sxe2_flow_parse_action.c',
'sxe2_flow_parse_pattern.c',
'sxe2_flow_parse_engine.c',
+ 'sxe2_dump.c',
)
diff --git a/drivers/net/sxe2/sxe2_dump.c b/drivers/net/sxe2/sxe2_dump.c
new file mode 100644
index 0000000000..1753eccf99
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_dump.c
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_malloc.h>
+#include <arpa/inet.h>
+
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_dump.h"
+#include "sxe2_stats.h"
+
+static void
+sxe2_dump_dev_feature_capability(FILE *file, struct rte_eth_dev *dev)
+{
+ uint32_t i;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ const struct {
+ uint32_t cap_bit;
+ const char *name;
+ } caps_name[] = {
+ {SXE2_DEV_CAPS_OFFLOAD_L2, "L2"},
+ {SXE2_DEV_CAPS_OFFLOAD_VLAN, "VLAN"},
+ {SXE2_DEV_CAPS_OFFLOAD_IPSEC, "IPSEC"},
+ {SXE2_DEV_CAPS_OFFLOAD_RSS, "RSS"},
+ {SXE2_DEV_CAPS_OFFLOAD_FNAV, "FNAV"},
+ {SXE2_DEV_CAPS_OFFLOAD_TM, "TM"},
+ {SXE2_DEV_CAPS_OFFLOAD_PTP, "PTP"},
+ };
+ if (adapter->is_dev_repr)
+ goto l_end;
+
+ fprintf(file, " - Dev Capability:\n");
+ for (i = 0; i < RTE_DIM(caps_name); i++) {
+ fprintf(file, "\t -- support %s: %s\n", caps_name[i].name,
+ (adapter->cap_flags & caps_name[i].cap_bit) ? "Yes" :
+ "No");
+ }
+l_end:
+ return;
+}
+
+static void
+sxe2_dump_device_basic_info(FILE *file, struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ fprintf(file,
+ " - Device Base Info:\n"
+ "\t -- name: %s\n"
+ "\t -- pf_idx: %u port_idx: %u\n"
+ "\t -- tx_mode_flags: 0x%x rx_mode_flags: 0x%x\n"
+ "\t -- flow_isolate_cfg: 0x%x flow_isolated: 0x%x\n"
+ "\t -- dev_type: 0x%x is_switchdev: 0x%x\n"
+ "\t -- is_dev_repr: 0x%x dev_port_id: 0x%x\n"
+ "\t -- dev_flags: 0x%x\n"
+ "\t -- intr_conf lsc: %u rxq: %u rmv: %u\n",
+ dev->data->name,
+ adapter->pf_idx, adapter->port_idx,
+ adapter->tx_mode_flags, adapter->rx_mode_flags,
+ adapter->flow_isolate_cfg, adapter->flow_isolated,
+ adapter->dev_type, adapter->switchdev_info.is_switchdev,
+ adapter->is_dev_repr, adapter->dev_port_id,
+ dev->data->dev_flags,
+ dev->data->dev_conf.intr_conf.lsc,
+ dev->data->dev_conf.intr_conf.rxq,
+ dev->data->dev_conf.intr_conf.rmv);
+}
+
+static void
+sxe2_dump_dev_args_info(FILE *file, struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ if (adapter->is_dev_repr)
+ goto l_end;
+
+ fprintf(file,
+ " - Device Args Info:\n"
+ "\t -- sw-stats-en: %s\n"
+ "\t -- high-performance-mode: %s\n"
+ "\t -- flow-duplicate-pattern: %u\n"
+ "\t -- fnav-stat-type: %u\n"
+ "\t -- sched_layer_mode: %u\n"
+ "\t -- rx_low_latency: %s\n"
+ "\t -- function-flow-direct: %s\n",
+ adapter->devargs.sw_stats_en ? "On" : "Off",
+ adapter->devargs.high_performance_mode ? "On" : "Off",
+ adapter->devargs.flow_dup_pattern_mode,
+ adapter->devargs.fnav_stat_type,
+ adapter->devargs.sched_layer_mode,
+ adapter->devargs.rx_low_latency ? "On" : "Off",
+ adapter->devargs.func_flow_direct_en ? "On" : "Off");
+l_end:
+ return;
+}
+
+static void sxe2_dump_filter_info(FILE *file, struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_mac_filter *mac_entry;
+ struct sxe2_mac_filter *next_mac_entry;
+ struct sxe2_vlan_filter *vlan_entry;
+ struct sxe2_vlan_filter *next_vlan_entry;
+
+ if (adapter->is_dev_repr)
+ goto l_end;
+
+ fprintf(file,
+ " - Device Filter Info:\n"
+ "\t -- cur_promisc:0x%x hw_promisc:0x%x\n"
+ "\t -- unicast_num: %u multicast_num: %u\n"
+ "\t -- vlan_num: %u filter_on: %u hw_filter_on: %u\n"
+ "\t -- vlan max_cnt: %u cnt: %u\n"
+ "\t -- tpid: 0x%x vid: 0x%x\n"
+ "\t -- vlan_outer_insert: 0x%x vlan_outer_strip: 0x%x\n"
+ "\t -- vlan_inner_insert: 0x%x vlan_inner_strip: 0x%x\n",
+ adapter->filter_ctxt.cur_promisc_flags,
+ adapter->filter_ctxt.hw_promisc_flags,
+ adapter->filter_ctxt.uc_num,
+ adapter->filter_ctxt.mc_num,
+ adapter->filter_ctxt.vlan_num,
+ adapter->filter_ctxt.vlan_info.filter_on,
+ adapter->filter_ctxt.vlan_info.hw_filter_on,
+ adapter->filter_ctxt.vlan_info.max_cnt,
+ adapter->filter_ctxt.vlan_info.cnt,
+ adapter->filter_ctxt.vlan_info.tpid,
+ adapter->filter_ctxt.vlan_info.vid,
+ adapter->filter_ctxt.vlan_info.outer_insert,
+ adapter->filter_ctxt.vlan_info.outer_strip,
+ adapter->filter_ctxt.vlan_info.inner_insert,
+ adapter->filter_ctxt.vlan_info.inner_strip);
+
+ if (adapter->filter_ctxt.uc_num > 0) {
+ fprintf(file,
+ "\t -- Unicast entry:\n");
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.uc_list, next,
+ next_mac_entry) {
+ fprintf(file,
+ "\t -- addr: %02x:%02x:%02x:%02x:%02x:%02x hw status:%u "
+ "default:%u\n",
+ mac_entry->mac_addr.addr_bytes[0],
+ mac_entry->mac_addr.addr_bytes[1],
+ mac_entry->mac_addr.addr_bytes[2],
+ mac_entry->mac_addr.addr_bytes[3],
+ mac_entry->mac_addr.addr_bytes[4],
+ mac_entry->mac_addr.addr_bytes[5],
+ mac_entry->hw_config,
+ mac_entry->default_config);
+ }
+ }
+
+ if (adapter->filter_ctxt.mc_num > 0) {
+ fprintf(file,
+ "\t -- Multicast entry:\n");
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.mc_list,
+ next, next_mac_entry) {
+ fprintf(file,
+ "\t -- addr: %02x:%02x:%02x:%02x:%02x:%02x "
+ "hw status:%u default:%u\n",
+ mac_entry->mac_addr.addr_bytes[0],
+ mac_entry->mac_addr.addr_bytes[1],
+ mac_entry->mac_addr.addr_bytes[2],
+ mac_entry->mac_addr.addr_bytes[3],
+ mac_entry->mac_addr.addr_bytes[4],
+ mac_entry->mac_addr.addr_bytes[5],
+ mac_entry->hw_config,
+ mac_entry->default_config);
+ }
+ }
+
+ if (adapter->filter_ctxt.vlan_num > 0) {
+ fprintf(file,
+ "\t -- Vlan entry:\n");
+ RTE_TAILQ_FOREACH_SAFE(vlan_entry, &adapter->filter_ctxt.vlan_list,
+ next, next_vlan_entry) {
+ fprintf(file,
+ "\t -- vlan tpid:0x%04x vid:0x%04x prio:%d "
+ "hw status:%u default:%u\n",
+ vlan_entry->vlan_info.tpid,
+ vlan_entry->vlan_info.vid,
+ vlan_entry->vlan_info.prio,
+ vlan_entry->hw_config,
+ vlan_entry->default_config);
+ }
+ }
+l_end:
+ return;
+}
+
+static const char *sxe2_vsi_id_str(uint16_t vsi_id, char *buf, size_t len)
+{
+ if (vsi_id == SXE2_INVALID_VSI_ID)
+ return "NA";
+
+ snprintf(buf, len, "%u", vsi_id);
+ return buf;
+}
+
+static void
+sxe2_dump_switchdev_info(FILE *file, struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ uint32_t idx;
+ char k_vsi_buf[16];
+ char u_vsi_buf[16];
+
+ if (adapter->is_dev_repr && adapter->repr_priv_data) {
+ fprintf(file,
+ " - Reprenstor Info:\n"
+ "\t -- repr_id: %u\n"
+ "\t -- repr_q_id: %u\n"
+ "\t -- repr_pf_id: %u\n"
+ "\t -- repr_vf_id: %u\n"
+ "\t -- repr_vf_vsi_id: %u\n"
+ "\t -- repr_vf_k_vsi_id: %s\n"
+ "\t -- repr_vf_u_vsi_id: %s\n",
+ adapter->repr_priv_data->repr_id,
+ adapter->repr_priv_data->repr_q_id,
+ adapter->repr_priv_data->repr_pf_id,
+ adapter->repr_priv_data->repr_vf_id,
+ adapter->repr_priv_data->repr_vf_vsi_id,
+ sxe2_vsi_id_str(adapter->repr_priv_data->repr_vf_k_vsi_id,
+ k_vsi_buf, sizeof(k_vsi_buf)),
+ sxe2_vsi_id_str(adapter->repr_priv_data->repr_vf_u_vsi_id,
+ u_vsi_buf, sizeof(u_vsi_buf)));
+ goto l_end;
+ }
+ if (adapter->switchdev_info.is_switchdev) {
+ fprintf(file,
+ " - Switchdev Info:\n"
+ "\t -- primary:0x%x\n"
+ "\t -- representor: 0x%x\n"
+ "\t -- port_name_type: 0x%x\n"
+ "\t -- nb_vf: %u nb_repr_vf: %u\n",
+ adapter->switchdev_info.primary,
+ adapter->switchdev_info.representor,
+ adapter->switchdev_info.port_name_type,
+ adapter->repr_ctxt.nb_vf,
+ adapter->repr_ctxt.nb_repr_vf);
+ if (adapter->repr_ctxt.nb_vf > 0) {
+ fprintf(file,
+ "\t -- vf entry:\n");
+ for (idx = 0; idx < adapter->repr_ctxt.nb_vf; idx++) {
+ fprintf(file,
+ "\t -- func_id:%u vsi_type:%u kernel_vsi_id:%u dpdk_vsi_id:%u\n",
+ adapter->repr_ctxt.repr_vf_id[idx].func_id,
+ adapter->repr_ctxt.repr_vf_id[idx].vsi_type,
+ adapter->repr_ctxt.repr_vf_id[idx].kernel_vsi_id,
+ adapter->repr_ctxt.repr_vf_id[idx].dpdk_vsi_id);
+ }
+ }
+ }
+
+l_end:
+ return;
+}
+
+int32_t sxe2_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file)
+{
+ char *buf = NULL;
+ size_t size = 0;
+ FILE *str;
+ int32_t ret = -1;
+
+ str = open_memstream(&buf, &size);
+ if (!str) {
+ PMD_LOG_ERR(DRV, "fopen fail.");
+ goto l_end;
+ }
+
+ sxe2_dump_dev_feature_capability(str, dev);
+ sxe2_dump_device_basic_info(str, dev);
+ sxe2_dump_dev_args_info(str, dev);
+ sxe2_dump_filter_info(str, dev);
+ sxe2_dump_switchdev_info(str, dev);
+
+ (void)fflush(str);
+
+ (void)fwrite(buf, 1, size, file);
+ (void)fflush(file);
+
+ ret = 0;
+
+ (void)fclose(str);
+ free(buf);
+l_end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_dump.h b/drivers/net/sxe2/sxe2_dump.h
new file mode 100644
index 0000000000..05d6db9b3d
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_dump.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_DUMP_H__
+#define __SXE2_DUMP_H__
+
+#include <ethdev_driver.h>
+
+int32_t sxe2_eth_dev_priv_dump(struct rte_eth_dev *dev, FILE *file);
+
+#endif /* __SXE2_DUMP_H__ */
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index d2b884c6cd..3c86424c15 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -38,6 +38,7 @@
#include "sxe2_host_regs.h"
#include "sxe2_switchdev.h"
#include "sxe2_ioctl_chnl_func.h"
+#include "sxe2_dump.h"
#include "sxe2_ethdev_repr.h"
#include "sxe2vf_regs.h"
#include "sxe2_switchdev.h"
@@ -194,6 +195,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.get_module_info = sxe2_get_module_info,
.get_module_eeprom = sxe2_get_module_eeprom,
+
+ .eth_dev_priv_dump = sxe2_eth_dev_priv_dump,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
diff --git a/drivers/net/sxe2/sxe2_ethdev_repr.c b/drivers/net/sxe2/sxe2_ethdev_repr.c
index a43991c379..faac1b2701 100644
--- a/drivers/net/sxe2/sxe2_ethdev_repr.c
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.c
@@ -12,6 +12,7 @@
#include "sxe2_switchdev.h"
#include "sxe2_ptype.h"
#include "sxe2_mp.h"
+#include "sxe2_dump.h"
#include "sxe2_stats.h"
#include "sxe2_flow.h"
@@ -237,6 +238,8 @@ static const struct eth_dev_ops sxe2_switchdev_repr_dev_ops = {
.allmulticast_enable = sxe2_repr_allmulti_enable,
.allmulticast_disable = sxe2_repr_allmulti_disable,
+ .eth_dev_priv_dump = sxe2_eth_dev_priv_dump,
+
.stats_get = sxe2_stats_info_get,
.stats_reset = sxe2_stats_info_reset,
.xstats_get = sxe2_xstats_info_get,
--
2.52.0
^ permalink raw reply related
* [PATCH v14 13/20] net/sxe2: support firmware version reading
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
This patch implements the logic to retrieve the firmware version and
Build ID from the hardware during device initialization.
The version is exposed to applications through the dev_info_get API.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/sxe2_ethdev.c | 35 +++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 58b56428f9..74b841c2ef 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -120,7 +120,8 @@ static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *tunnel_udp);
static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev,
struct rte_eth_udp_tunnel *tunnel_udp);
-
+static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev,
+ char *fw_version, size_t fw_size);
static const struct eth_dev_ops sxe2_eth_dev_ops = {
.dev_configure = sxe2_dev_configure,
@@ -181,6 +182,8 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.xstats_reset = sxe2_stats_info_reset,
.queue_stats_mapping_set = sxe2_queue_stats_mapping_set,
+
+ .fw_version_get = sxe2_fw_version_string_get,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -1575,6 +1578,36 @@ static int32_t sxe2_eth_pmd_remove(struct sxe2_common_device *cdev)
return ret;
}
+static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
+{
+ struct sxe2_adapter *adapter =
+ SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_fw_info *fw_info = &adapter->dev_info.fw;
+ int32_t ret_len;
+ int32_t ret;
+
+ ret_len = snprintf(fw_version, fw_size,
+ "%u.%u.%u.%u",
+ fw_info->main_version_id,
+ fw_info->sub_version_id,
+ fw_info->fix_version_id,
+ fw_info->build_id);
+
+ if (ret_len < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret_len += 1;
+ if (fw_size < (size_t)ret_len)
+ ret = -EINVAL;
+ else
+ ret = 0;
+
+out:
+ return ret;
+}
+
static uint16_t sxe2_switchdev_repr_id_encode_get(struct sxe2_switchdev_info *switchdev_info)
{
enum rte_eth_representor_type type;
--
2.52.0
^ permalink raw reply related
* [PATCH v14 04/20] net/sxe2: support L2 filtering and MAC config
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
- Support primary/secondary MAC address setup.
- Enable L2 broadcast/multicast filter bits.
- Add multicast address update logic.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 1 +
drivers/net/sxe2/sxe2_cmd_chnl.c | 198 ++++++++
drivers/net/sxe2/sxe2_cmd_chnl.h | 17 +
drivers/net/sxe2/sxe2_drv_cmd.h | 87 ++++
drivers/net/sxe2/sxe2_ethdev.c | 70 ++-
drivers/net/sxe2/sxe2_ethdev.h | 43 +-
drivers/net/sxe2/sxe2_filter.c | 782 ++++++++++++++++++++++++++++++
drivers/net/sxe2/sxe2_filter.h | 98 ++++
drivers/net/sxe2/sxe2_mac.c | 432 +++++++++++++++++
drivers/net/sxe2/sxe2_mac.h | 34 ++
drivers/net/sxe2/sxe2_txrx_poll.c | 49 ++
11 files changed, 1805 insertions(+), 6 deletions(-)
create mode 100644 drivers/net/sxe2/sxe2_filter.c
create mode 100644 drivers/net/sxe2/sxe2_filter.h
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index b14b5120c1..b661e3cbf4 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -61,4 +61,5 @@ sources += files(
'sxe2_txrx.c',
'sxe2_txrx_vec.c',
'sxe2_mac.c',
+ 'sxe2_filter.c',
)
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.c b/drivers/net/sxe2/sxe2_cmd_chnl.c
index 07eeb7f38c..1fa9ad718e 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.c
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.c
@@ -343,3 +343,201 @@ int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter)
l_end:
return ret;
}
+
+int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_promisc_filter_cfg_req promisc_filter_cfg_req = {0};
+
+ promisc_filter_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ promisc_filter_cfg_req.is_add = set;
+ promisc_filter_cfg_req.type = SXE2_PROMISC_FILTER_TYPE_PROMISC;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_PROMISC_CFG,
+ &promisc_filter_cfg_req,
+ sizeof(promisc_filter_cfg_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "promic config failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_promisc_filter_cfg_req promisc_filter_cfg_req = {0};
+
+ promisc_filter_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ promisc_filter_cfg_req.is_add = set;
+ promisc_filter_cfg_req.type = SXE2_PROMISC_FILTER_TYPE_ALLMULTI;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_ALLMULTI_CFG,
+ &promisc_filter_cfg_req,
+ sizeof(promisc_filter_cfg_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "allmulti config failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add)
+{
+ int32_t ret = 0;
+ int32_t i;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_mac_filter_cfg_req mac_filter_cfg_req = {0};
+
+ mac_filter_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ for (i = 0; i < SXE2_ETH_ALEN; i++)
+ mac_filter_cfg_req.addr[i] = addr->addr_bytes[i];
+ mac_filter_cfg_req.is_add = add;
+ mac_filter_cfg_req.type = SXE2_MAC_FILTER_TYPE_UC;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_MAC_ADDR_UC,
+ &mac_filter_cfg_req, sizeof(mac_filter_cfg_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "uc config query failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_mc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add)
+{
+ int32_t ret = 0;
+ int32_t i;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_mac_filter_cfg_req mac_filter_cfg_req = {0};
+
+ mac_filter_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ for (i = 0; i < SXE2_ETH_ALEN; i++)
+ mac_filter_cfg_req.addr[i] = addr->addr_bytes[i];
+
+ mac_filter_cfg_req.is_add = add;
+ mac_filter_cfg_req.type = SXE2_MAC_FILTER_TYPE_MC;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_MAC_ADDR_MC,
+ &mac_filter_cfg_req, sizeof(mac_filter_cfg_req),
+ NULL, 0);
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "mac config query failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_vlan_config_query(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_drv_vlan_cfg_query_resp vlan_cfg_query_resp = {0};
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VLAN_CFG_QUERY,
+ NULL, 0,
+ &vlan_cfg_query_resp,
+ sizeof(vlan_cfg_query_resp));
+
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "vlan config query failed, ret=%d", ret);
+
+ adapter->filter_ctxt.vlan_info.port_vlan_exist = vlan_cfg_query_resp.port_vlan_exist;
+ adapter->filter_ctxt.vlan_info.is_switchdev = vlan_cfg_query_resp.is_switchdev;
+
+
+ adapter->filter_ctxt.vlan_info.tpid = vlan_cfg_query_resp.tpid;
+ adapter->filter_ctxt.vlan_info.vid = vlan_cfg_query_resp.vid;
+
+ adapter->filter_ctxt.vlan_info.outer_insert = vlan_cfg_query_resp.outer_insert;
+ adapter->filter_ctxt.vlan_info.outer_strip = vlan_cfg_query_resp.outer_strip;
+ adapter->filter_ctxt.vlan_info.inner_insert = vlan_cfg_query_resp.inner_insert;
+ adapter->filter_ctxt.vlan_info.inner_strip = vlan_cfg_query_resp.inner_strip;
+
+ return ret;
+}
+
+int32_t sxe2_drv_vlan_filter_id_config(struct sxe2_adapter *adapter,
+ struct sxe2_vlan *vlan, bool on)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_vlan_filter_cfg_req vlan_filter_cfg_req = {0};
+
+ vlan_filter_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ vlan_filter_cfg_req.tpid_id = vlan->tpid;
+ vlan_filter_cfg_req.vlan_id = vlan->vid;
+ vlan_filter_cfg_req.prio = vlan->prio;
+ vlan_filter_cfg_req.is_add = on;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VLAN_FILTER_ADD_DEL,
+ &vlan_filter_cfg_req, sizeof(vlan_filter_cfg_req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "vlan config failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_vlan_insert_strip_cfg(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_drv_vlan_offload_cfg_req vlan_offload_cfg_req = {0};
+
+ vlan_offload_cfg_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ vlan_offload_cfg_req.tpid = adapter->filter_ctxt.vlan_info.tpid;
+ vlan_offload_cfg_req.outer_insert = adapter->filter_ctxt.vlan_info.outer_insert;
+ vlan_offload_cfg_req.outer_strip = adapter->filter_ctxt.vlan_info.outer_strip;
+ vlan_offload_cfg_req.inner_insert = adapter->filter_ctxt.vlan_info.inner_insert;
+ vlan_offload_cfg_req.inner_strip = adapter->filter_ctxt.vlan_info.inner_strip;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VLAN_OFFLOAD_CFG,
+ &vlan_offload_cfg_req,
+ sizeof(vlan_offload_cfg_req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "vlan config query failed, ret=%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_drv_vlan_filter_switch(struct sxe2_adapter *adapter, bool on)
+{
+ int32_t ret = 0;
+ struct sxe2_common_device *cdev = adapter->cdev;
+ struct sxe2_drv_cmd_params param = {0};
+ struct sxe2_vlan_filter_switch_req vlan_filter_switch_req = {0};
+
+ vlan_filter_switch_req.vsi_id = adapter->vsi_ctxt.dpdk_vsi_id;
+ vlan_filter_switch_req.is_oper_enable = on;
+
+ sxe2_drv_cmd_params_fill(adapter, ¶m, SXE2_DRV_CMD_VLAN_FILTER_SWITCH,
+ &vlan_filter_switch_req,
+ sizeof(vlan_filter_switch_req),
+ NULL, 0);
+ ret = sxe2_drv_cmd_exec(cdev, ¶m);
+ if (ret)
+ PMD_DEV_LOG_WARN(adapter, DRV, "vlan config filter failed, ret=%d", ret);
+
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_cmd_chnl.h b/drivers/net/sxe2/sxe2_cmd_chnl.h
index cda676ed97..c93bc2b0c9 100644
--- a/drivers/net/sxe2/sxe2_cmd_chnl.h
+++ b/drivers/net/sxe2/sxe2_cmd_chnl.h
@@ -36,4 +36,21 @@ int32_t sxe2_drv_txq_ctxt_cfg(struct sxe2_adapter *adapter,
int32_t sxe2_drv_mac_link_status_get(struct sxe2_adapter *adapter);
+int32_t sxe2_drv_promisc_config(struct sxe2_adapter *adapter, bool set);
+
+int32_t sxe2_drv_allmulti_config(struct sxe2_adapter *adapter, bool set);
+
+int32_t sxe2_drv_uc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
+
+int32_t sxe2_drv_mc_config(struct sxe2_adapter *adapter, struct rte_ether_addr *addr, bool add);
+
+int32_t sxe2_drv_vlan_config_query(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_vlan_filter_id_config(struct sxe2_adapter *adapter,
+ struct sxe2_vlan *vlan, bool on);
+
+int32_t sxe2_drv_vlan_insert_strip_cfg(struct sxe2_adapter *adapter);
+
+int32_t sxe2_drv_vlan_filter_switch(struct sxe2_adapter *adapter, bool on);
+
#endif /* SXE2_CMD_CHNL_H */
diff --git a/drivers/net/sxe2/sxe2_drv_cmd.h b/drivers/net/sxe2/sxe2_drv_cmd.h
index a0f08b5184..d69d650148 100644
--- a/drivers/net/sxe2/sxe2_drv_cmd.h
+++ b/drivers/net/sxe2/sxe2_drv_cmd.h
@@ -233,6 +233,93 @@ struct __rte_aligned(4) __rte_packed_begin sxe2_drv_link_info_resp {
uint8_t rsv[3];
} __rte_packed_end;
+struct __rte_aligned(4) __rte_packed_begin sxe2_switchdev_info {
+ uint8_t is_switchdev;
+ uint8_t primary;
+ uint8_t representor;
+ uint8_t port_name_type;
+ uint32_t ctrl_num;
+ uint32_t pf_num;
+ uint32_t vf_num;
+ uint32_t mpesw_owner;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vlan_cfg_query_resp {
+ uint16_t vsi_id;
+ uint8_t port_vlan_exist;
+ uint8_t is_switchdev;
+ uint16_t tpid;
+ uint16_t vid;
+ uint8_t outer_insert;
+ uint8_t outer_strip;
+ uint8_t inner_insert;
+ uint8_t inner_strip;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_vlan_offload_cfg_req {
+ uint16_t vsi_id;
+ uint16_t tpid;
+ uint8_t outer_insert;
+ uint8_t outer_strip;
+ uint8_t inner_insert;
+ uint8_t inner_strip;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_drv_port_vlan_cfg_req {
+ uint16_t vsi_id;
+ uint16_t tpid;
+ uint16_t vid;
+ uint8_t prio;
+ uint8_t rsv;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_mac_filter_cfg_req {
+ uint16_t vsi_id;
+ uint8_t addr[SXE2_ETH_ALEN];
+ uint8_t type;
+ uint8_t is_add;
+ uint8_t rsv[2];
+} __rte_packed_end;
+
+enum sxe2_promisc_filter_type {
+ SXE2_PROMISC_FILTER_TYPE_PROMISC = 0,
+ SXE2_PROMISC_FILTER_TYPE_ALLMULTI,
+ SXE2_PROMISC_FILTER_TYPE_MAX,
+};
+
+enum sxe2_mac_filter_type {
+ SXE2_MAC_FILTER_TYPE_UC = 0,
+ SXE2_MAC_FILTER_TYPE_MC,
+ SXE2_MAC_FILTER_TYPE_MAX,
+};
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_promisc_filter_cfg_req {
+ uint16_t vsi_id;
+ uint8_t type;
+ uint8_t is_add;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_srcvsi_ext_cfg_req {
+ uint16_t vsi_id;
+ uint16_t srcvsi_list[SXE2_SRCVSI_PRUNE_MAX_NUM];
+ uint8_t srcvsi_cnt;
+ uint8_t is_add;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_vlan_filter_cfg_req {
+ uint16_t vsi_id;
+ uint16_t vlan_id;
+ uint16_t tpid_id;
+ uint8_t prio;
+ uint8_t is_add;
+} __rte_packed_end;
+
+struct __rte_aligned(4) __rte_packed_begin sxe2_vlan_filter_switch_req {
+ uint16_t vsi_id;
+ uint8_t is_oper_enable;
+ uint8_t rsv;
+} __rte_packed_end;
+
enum sxe2_drv_cmd_module {
SXE2_DRV_CMD_MODULE_HANDSHAKE = 0,
SXE2_DRV_CMD_MODULE_DEV = 1,
diff --git a/drivers/net/sxe2/sxe2_ethdev.c b/drivers/net/sxe2/sxe2_ethdev.c
index 80881595d6..4ffe32d353 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -111,8 +111,20 @@ static const struct eth_dev_ops sxe2_eth_dev_ops = {
.tx_burst_mode_get = sxe2_tx_burst_mode_get,
.tx_done_cleanup = sxe2_tx_done_cleanup,
+ .promiscuous_enable = sxe2_promisc_enable,
+ .promiscuous_disable = sxe2_promisc_disable,
+ .allmulticast_enable = sxe2_allmulti_enable,
+ .allmulticast_disable = sxe2_allmulti_disable,
+
+ .mac_addr_add = sxe2_mac_addr_add,
+ .mac_addr_remove = sxe2_mac_addr_del,
+ .mac_addr_set = sxe2_mac_addr_set,
+ .set_mc_addr_list = sxe2_set_mc_addr_list,
.mtu_set = sxe2_mtu_set,
.buffer_split_supported_hdr_ptypes_get = sxe2_buffer_split_supported_hdr_ptypes_get,
+
+ .vlan_filter_set = sxe2_dev_vlan_filter_set,
+ .vlan_offload_set = sxe2_dev_vlan_offload_set,
};
static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
@@ -123,6 +135,13 @@ static int32_t sxe2_dev_configure(struct rte_eth_dev *dev)
if (dev->data->dev_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG)
dev->data->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH;
+ ret = sxe2_vlan_default_cfg(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to init vlan, ret=%d", ret);
+ goto end;
+ }
+
+end:
return ret;
}
@@ -138,6 +157,8 @@ static int32_t sxe2_dev_stop(struct rte_eth_dev *dev)
sxe2_txqs_all_stop(dev);
sxe2_rxqs_all_stop(dev);
+ (void)sxe2_filter_rule_stop(dev);
+
dev->data->dev_started = 0;
adapter->started = 0;
l_end:
@@ -165,16 +186,23 @@ static int32_t sxe2_dev_start(struct rte_eth_dev *dev)
goto l_end;
}
+ ret = sxe2_filter_rule_start(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to add all mc addr to fw.");
+ goto l_end;
+ }
+
ret = sxe2_queues_start(dev);
if (ret) {
PMD_LOG_ERR(INIT, "enable queues failed");
- goto l_end;
+ goto l_start_queues_err;
}
dev->data->dev_started = 1;
adapter->started = 1;
goto l_end;
-
+l_start_queues_err:
+ (void)sxe2_filter_rule_stop(dev);
l_end:
return ret;
}
@@ -194,6 +222,7 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
dev_info->min_mtu = RTE_ETHER_MIN_MTU;
dev_info->rx_offload_capa =
+ RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
RTE_ETH_RX_OFFLOAD_KEEP_CRC |
RTE_ETH_RX_OFFLOAD_SCATTER |
RTE_ETH_RX_OFFLOAD_IPV4_CKSUM |
@@ -202,9 +231,15 @@ static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev,
RTE_ETH_RX_OFFLOAD_SCTP_CKSUM |
RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM |
RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT |
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+ RTE_ETH_RX_OFFLOAD_QINQ_STRIP |
+#endif
+ RTE_ETH_RX_OFFLOAD_VLAN_EXTEND |
RTE_ETH_RX_OFFLOAD_TCP_LRO;
dev_info->tx_offload_capa =
+ RTE_ETH_TX_OFFLOAD_VLAN_INSERT |
+ RTE_ETH_TX_OFFLOAD_QINQ_INSERT |
RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE |
RTE_ETH_TX_OFFLOAD_IPV4_CKSUM |
@@ -428,6 +463,12 @@ static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
{
int32_t ret = 0;
+ ret = sxe2_filter_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize l2 filter, ret:%d", ret);
+ goto l_end;
+ }
+
ret = sxe2_link_update_init(dev);
if (ret) {
PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret);
@@ -439,12 +480,37 @@ static int32_t sxe2_eth_init(struct rte_eth_dev *dev)
PMD_LOG_ERR(INIT, "Failed to set mtu, ret=%d", ret);
goto l_end;
}
+
+ ret = sxe2_mac_addr_init(dev);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to initialize mac address, ret:%d", ret);
+ goto l_end;
+ }
+
+ ret = sxe2_mac_default_cfg(dev);
+ if (ret != 0) {
+ PMD_LOG_ERR(INIT, "Failed to configure default mac address, ret:%d", ret);
+ goto l_err;
+ }
+
+ ret = sxe2_vlan_cfg_init(dev);
+ if (ret) {
+ PMD_LOG_ERR(INIT, "Failed to initialize vlan config, ret:%d", ret);
+ goto l_err;
+ }
+ goto l_end;
+
+l_err:
+ sxe2_mac_addr_uinit(dev);
+ (void)sxe2_filter_uinit(dev);
l_end:
return ret;
}
static void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused)
{
+ sxe2_mac_addr_uinit(dev);
+ (void)sxe2_filter_uinit(dev);
}
static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter,
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index 9de47d8338..fa3c69d360 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -15,9 +15,11 @@
#include "sxe2_common.h"
#include "sxe2_vsi.h"
-#include "sxe2_queue.h"
#include "sxe2_irq.h"
+#include "sxe2_queue.h"
+#include "sxe2_mac.h"
#include "sxe2_osal.h"
+#include "sxe2_filter.h"
struct sxe2_link_msg {
uint32_t speed;
@@ -35,7 +37,7 @@ enum sxe2_fnav_tunnel_flag_type {
#define SXE2_FRAME_SIZE_MAX 9832
#define SXE2_VLAN_TAG_SIZE 4
#define SXE2_ETH_OVERHEAD \
- (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + SXE2_VLAN_TAG_SIZE)
+ (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + 2 * SXE2_VLAN_TAG_SIZE)
#define SXE2_ETH_MAX_LEN (RTE_ETHER_MTU + SXE2_ETH_OVERHEAD)
#ifdef SXE2_TEST
@@ -267,6 +269,27 @@ struct sxe2_link_context {
uint32_t speed;
};
+struct sxe2_filter_context {
+ rte_spinlock_t filter_lock;
+ struct sxe2_vlan_info vlan_info;
+ struct sxe2_uc_filter_list_head uc_list;
+ struct sxe2_mc_filter_list_head mc_list;
+ struct sxe2_vlan_filter_list_head vlan_list;
+ uint8_t uc_num;
+ uint8_t mc_num;
+ uint8_t vlan_num;
+ uint8_t rsv;
+ uint32_t hw_promisc_flags;
+ uint32_t cur_promisc_flags;
+
+ bool hw_uplink_config;
+ bool cur_uplink_config;
+ bool hw_repr_config;
+ bool cur_repr_config;
+ bool hw_l2_config;
+ bool cur_l2_config;
+};
+
struct sxe2_adapter {
struct sxe2_common_device *cdev;
struct sxe2_dev_info dev_info;
@@ -276,10 +299,14 @@ struct sxe2_adapter {
struct sxe2_irq_context irq_ctxt;
struct sxe2_queue_context q_ctxt;
struct sxe2_vsi_context vsi_ctxt;
+ struct sxe2_filter_context filter_ctxt;
struct sxe2_link_context link_ctxt;
struct sxe2_devargs devargs;
- uint16_t dev_port_id;
- uint64_t cap_flags;
+ struct sxe2_switchdev_info switchdev_info;
+ bool rule_started;
+ bool flow_isolated;
+ uint16_t dev_port_id;
+ uint64_t cap_flags;
enum sxe2_dev_type dev_type;
uint32_t ptype_tbl[SXE2_MAX_PTYPE_NUM];
struct rte_ether_addr mac_addr;
@@ -315,4 +342,12 @@ int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev);
void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev);
+static inline bool
+sxe2_dev_port_vlan_check(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ return ad->filter_ctxt.vlan_info.port_vlan_exist;
+}
+
#endif /* SXE2_ETHDEV_H */
diff --git a/drivers/net/sxe2/sxe2_filter.c b/drivers/net/sxe2/sxe2_filter.c
new file mode 100644
index 0000000000..b2a726f77e
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_filter.c
@@ -0,0 +1,782 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_os.h>
+#include <rte_tailq.h>
+#include "sxe2_osal.h"
+#include "sxe2_mac.h"
+#include "sxe2_common_log.h"
+#include "sxe2_ethdev.h"
+#include "sxe2_cmd_chnl.h"
+
+static struct sxe2_mac_filter *sxe2_uc_filter_find(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *macaddr)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ struct sxe2_mac_filter *entry = NULL;
+ struct sxe2_mac_filter *next_entry = NULL;
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ RTE_TAILQ_FOREACH_SAFE(entry, &adapter->filter_ctxt.uc_list, next, next_entry) {
+ if (rte_is_same_ether_addr(macaddr, &entry->mac_addr)) {
+ filter = entry;
+ break;
+ }
+ }
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ return filter;
+}
+
+int32_t sxe2_uc_filter_add(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr, bool default_config)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ bool hw_config = false;
+ int32_t ret = 0;
+
+ filter = sxe2_uc_filter_find(adapter, mac_addr);
+ if (filter) {
+ if (default_config && !filter->default_config)
+ filter->default_config = true;
+ PMD_DEV_LOG_INFO(adapter, DRV, "This MAC filter already exists.");
+ goto l_end;
+ }
+
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot add hw uc addr in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add hw uc addr in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add hw uc addr in switchdev mode");
+ } else {
+ ret = sxe2_drv_uc_config(adapter, mac_addr, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add uc rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ hw_config = true;
+ }
+
+ filter = rte_zmalloc("sxe2_uc_filter",
+ sizeof(struct sxe2_mac_filter), 0);
+ if (!filter) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to allocate memory");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ filter->hw_config = hw_config;
+ filter->default_config = default_config;
+ rte_ether_addr_copy(mac_addr, &filter->mac_addr);
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_INSERT_TAIL(&adapter->filter_ctxt.uc_list, filter, next);
+ adapter->filter_ctxt.uc_num++;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ PMD_DEV_LOG_INFO(adapter, DRV, "add mac rule, mac num %u.", adapter->filter_ctxt.uc_num);
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_uc_filter_del(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ int32_t ret = -1;
+
+ filter = sxe2_uc_filter_find(adapter, mac_addr);
+ if (!filter) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "This MAC filter not exists.");
+ ret = 0;
+ goto l_end;
+ }
+ if (filter->hw_config) {
+ ret = sxe2_drv_uc_config(adapter, mac_addr, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete mac rule");
+ if (ret == -EPERM)
+ goto l_free;
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ PMD_DEV_LOG_INFO(adapter, DRV, "remove mac rule, uc num %u.", adapter->filter_ctxt.uc_num);
+ ret = 0;
+
+l_free:
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_REMOVE(&adapter->filter_ctxt.uc_list, filter, next);
+ adapter->filter_ctxt.uc_num--;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+ rte_free(filter);
+ filter = NULL;
+l_end:
+ return ret;
+}
+
+void sxe2_uc_filter_clear(struct sxe2_adapter *adapter, bool default_config)
+{
+ struct sxe2_mac_filter *entry;
+ struct sxe2_mac_filter *next_entry;
+
+ RTE_TAILQ_FOREACH_SAFE(entry, &adapter->filter_ctxt.uc_list, next, next_entry) {
+ if (entry->default_config && !default_config)
+ continue;
+
+ if (sxe2_uc_filter_del(adapter, &entry->mac_addr))
+ PMD_DEV_LOG_ERR(adapter, DRV, "This MAC filter delete fail.");
+ }
+}
+
+static struct sxe2_mac_filter *sxe2_mc_filter_find(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *macaddr)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ struct sxe2_mac_filter *entry = NULL;
+ struct sxe2_mac_filter *next_entry = NULL;
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ RTE_TAILQ_FOREACH_SAFE(entry, &adapter->filter_ctxt.mc_list, next, next_entry) {
+ if (rte_is_same_ether_addr(macaddr, &entry->mac_addr)) {
+ filter = entry;
+ break;
+ }
+ }
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ return filter;
+}
+
+int32_t sxe2_mc_filter_add(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr, bool default_config)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ bool hw_config = false;
+ int32_t ret = 0;
+
+ filter = sxe2_mc_filter_find(adapter, mac_addr);
+ if (filter) {
+ if (default_config && !filter->default_config)
+ filter->default_config = true;
+ PMD_DEV_LOG_INFO(adapter, DRV, "This MAC filter already exists.");
+ goto l_end;
+ }
+
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot add hw mc addr in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add hw mc addr in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add hw mc addr in switchdev mode");
+ } else {
+ ret = sxe2_drv_mc_config(adapter, mac_addr, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add mac rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ hw_config = true;
+ }
+
+ filter = rte_zmalloc("sxe2_mc_filter",
+ sizeof(struct sxe2_mac_filter), 0);
+ if (!filter) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to allocate memory");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+ filter->hw_config = hw_config;
+ filter->default_config = default_config;
+ rte_ether_addr_copy(mac_addr, &filter->mac_addr);
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_INSERT_TAIL(&adapter->filter_ctxt.mc_list, filter, next);
+ adapter->filter_ctxt.mc_num++;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ PMD_DEV_LOG_INFO(adapter, DRV, "add mc rule, mc num %u.", adapter->filter_ctxt.mc_num);
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_mc_filter_del(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr)
+{
+ struct sxe2_mac_filter *filter = NULL;
+ int32_t ret = -1;
+
+ filter = sxe2_mc_filter_find(adapter, mac_addr);
+ if (!filter) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "This MAC filter not exists.");
+ ret = 0;
+ goto l_end;
+ }
+
+ if (filter->hw_config) {
+ ret = sxe2_drv_mc_config(adapter, mac_addr, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete mc rule");
+ if (ret == -EPERM)
+ goto l_free;
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ PMD_DEV_LOG_INFO(adapter, DRV, "remove mc rule, mc num %u.", adapter->filter_ctxt.mc_num);
+ ret = 0;
+
+l_free:
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_REMOVE(&adapter->filter_ctxt.mc_list, filter, next);
+ adapter->filter_ctxt.mc_num--;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+ rte_free(filter);
+ filter = NULL;
+l_end:
+ return ret;
+}
+
+void sxe2_mc_filter_clear(struct sxe2_adapter *adapter, bool default_config)
+{
+ struct sxe2_mac_filter *entry;
+ struct sxe2_mac_filter *next_entry;
+
+ RTE_TAILQ_FOREACH_SAFE(entry, &adapter->filter_ctxt.mc_list, next, next_entry) {
+ if (entry->default_config && !default_config)
+ continue;
+ if (sxe2_mc_filter_del(adapter, &entry->mac_addr))
+ PMD_DEV_LOG_ERR(adapter, DRV, "This MAC filter delete fail.");
+ }
+}
+
+static struct sxe2_vlan_filter *sxe2_vlan_filter_find(struct sxe2_adapter *adapter,
+ struct sxe2_vlan *vlan)
+{
+ struct sxe2_vlan_filter *f;
+ struct sxe2_vlan_filter *save_f = NULL;
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_FOREACH(f, &adapter->filter_ctxt.vlan_list, next)
+ {
+ if (vlan->tpid == f->vlan_info.tpid &&
+ vlan->vid == f->vlan_info.vid) {
+ save_f = f;
+ break;
+ }
+ }
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ return save_f;
+}
+
+int32_t sxe2_vlan_filter_add(struct sxe2_adapter *adapter,
+ struct sxe2_vlan *vlan, bool default_config)
+{
+ struct sxe2_vlan_filter *filter = NULL;
+ bool hw_config = false;
+ int32_t ret = 0;
+
+ if (!vlan || vlan->vid > RTE_ETHER_MAX_VLAN_ID) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "This vlan filter is invalid.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ filter = sxe2_vlan_filter_find(adapter, vlan);
+ if (filter) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "This vlan filter already exists.");
+ ret = 0;
+ goto l_end;
+ }
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot add vlan in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add vlan in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add vlan in switchdev mode");
+ } else {
+ ret = sxe2_drv_vlan_filter_id_config(adapter, vlan, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add vlan rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ hw_config = true;
+ }
+
+ filter = rte_zmalloc("sxe2_vlan_filter", sizeof(*filter), 0);
+ if (!filter) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to allocate memory");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ filter->hw_config = hw_config;
+ filter->default_config = default_config;
+
+ filter->vlan_info.tpid = vlan->tpid;
+ filter->vlan_info.vid = vlan->vid;
+ filter->vlan_info.prio = vlan->prio;
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_INSERT_TAIL(&adapter->filter_ctxt.vlan_list, filter, next);
+ adapter->filter_ctxt.vlan_num++;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_vlan_filter_del(struct sxe2_adapter *adapter, struct sxe2_vlan *vlan)
+{
+ struct sxe2_vlan_filter *filter = NULL;
+ int32_t ret = -1;
+
+ if (!vlan || vlan->vid > RTE_ETHER_MAX_VLAN_ID) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "This vlan filter is invalid.");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ filter = sxe2_vlan_filter_find(adapter, vlan);
+ if (!filter) {
+ PMD_DEV_LOG_INFO(adapter, DRV, "This vlan filter not exists.");
+ ret = 0;
+ goto l_end;
+ }
+
+ if (filter->hw_config) {
+ ret = sxe2_drv_vlan_filter_id_config(adapter, vlan, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete vlan rule");
+ if (ret == -EPERM)
+ goto l_free;
+ ret = -EINVAL;
+ goto l_end;
+ }
+ }
+ ret = 0;
+
+l_free:
+
+ rte_spinlock_lock(&adapter->filter_ctxt.filter_lock);
+ TAILQ_REMOVE(&adapter->filter_ctxt.vlan_list, filter, next);
+ adapter->filter_ctxt.vlan_num--;
+ rte_spinlock_unlock(&adapter->filter_ctxt.filter_lock);
+ rte_free(filter);
+ filter = NULL;
+l_end:
+ return ret;
+}
+
+void sxe2_vlan_filters_clear(struct sxe2_adapter *adapter, bool default_config)
+{
+ int32_t ret = 0;
+ struct sxe2_vlan_filter *v_f;
+ void *temp;
+
+ if (adapter->filter_ctxt.vlan_num == 0)
+ return;
+
+ RTE_TAILQ_FOREACH_SAFE(v_f, &adapter->filter_ctxt.vlan_list, next, temp)
+ {
+ if (v_f->default_config && !default_config)
+ continue;
+ ret = sxe2_vlan_filter_del(adapter, &v_f->vlan_info);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "This vlan filter delete fail.");
+ }
+}
+
+int32_t sxe2_vlan_filter_ctrl(struct sxe2_adapter *adapter, bool flag)
+{
+ struct sxe2_vlan_info *vlan_info = &adapter->filter_ctxt.vlan_info;
+ int32_t ret = 0;
+
+ if (vlan_info->filter_on == flag)
+ goto l_end;
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot add vlan filter ctrl in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add vlan filter ctrl in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot add vlan filter ctrl in switchdev mode");
+ } else {
+ ret = sxe2_drv_vlan_filter_switch(adapter, flag);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add vlan filter ctrl");
+ goto l_end;
+ }
+ vlan_info->hw_filter_on = flag;
+ }
+ vlan_info->filter_on = flag;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_promisc_add(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot enable promiscuous in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot enable promiscuous in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot enable promiscuous in switchdev mode");
+ } else if (!(adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC)) {
+ ret = sxe2_drv_promisc_config(adapter, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg promiscuous, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags |= SXE2_PROMISC;
+ }
+ adapter->filter_ctxt.cur_promisc_flags |= SXE2_PROMISC;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_promisc_del(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->flow_isolated &&
+ (adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC)) {
+ ret = sxe2_drv_promisc_config(adapter, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg promiscuous, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags &= ~SXE2_PROMISC;
+ }
+
+ adapter->filter_ctxt.cur_promisc_flags &= ~SXE2_PROMISC;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_allmulti_add(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->rule_started) {
+ PMD_DEV_LOG_DEBUG(adapter, DRV, "cannot enable allmulticast in port stop status");
+ } else if (adapter->flow_isolated) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot enable allmulticast in flow isolation mode");
+ } else if (adapter->switchdev_info.is_switchdev) {
+ PMD_DEV_LOG_WARN(adapter, DRV, "cannot enable allmulticast in switchdev mode");
+ } else if (!(adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC_MULTICAST)) {
+ ret = sxe2_drv_allmulti_config(adapter, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg allmulticast, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags |= SXE2_PROMISC_MULTICAST;
+ }
+ adapter->filter_ctxt.cur_promisc_flags |= SXE2_PROMISC_MULTICAST;
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_allmulti_del(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->flow_isolated &&
+ (adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC_MULTICAST)) {
+ ret = sxe2_drv_allmulti_config(adapter, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg allmulticast, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags &= ~SXE2_PROMISC_MULTICAST;
+ }
+
+ adapter->filter_ctxt.cur_promisc_flags &= ~SXE2_PROMISC_MULTICAST;
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_all_filter_hw_clear(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ struct sxe2_mac_filter *mac_entry;
+ struct sxe2_mac_filter *next_mac_entry;
+ struct sxe2_vlan_filter *vlan_entry;
+ struct sxe2_vlan_filter *next_vlan_entry;
+
+ if (adapter->filter_ctxt.uc_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.uc_list, next,
+ next_mac_entry) {
+ if (mac_entry->hw_config) {
+ ret = sxe2_drv_uc_config(adapter, &mac_entry->mac_addr, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete mac rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ mac_entry->hw_config = false;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.mc_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.mc_list, next,
+ next_mac_entry) {
+ if (mac_entry->hw_config) {
+ ret = sxe2_drv_mc_config(adapter, &mac_entry->mac_addr, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete mc rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ mac_entry->hw_config = false;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.vlan_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(vlan_entry, &adapter->filter_ctxt.vlan_list, next,
+ next_vlan_entry) {
+ if (vlan_entry->hw_config) {
+ ret = sxe2_drv_vlan_filter_id_config(adapter,
+ &vlan_entry->vlan_info, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete vlan rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ vlan_entry->hw_config = false;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.vlan_info.hw_filter_on) {
+ ret = sxe2_drv_vlan_filter_switch(adapter, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to delete vlan rule");
+ ret = -EINVAL;
+ goto l_end;
+ }
+ adapter->filter_ctxt.vlan_info.hw_filter_on = false;
+ }
+
+ if (adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC) {
+ ret = sxe2_drv_promisc_config(adapter, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg promiscuous, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags &= ~SXE2_PROMISC;
+ }
+
+ if (adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC_MULTICAST) {
+ ret = sxe2_drv_allmulti_config(adapter, false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "failed to cfg allmulticast, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags &= ~SXE2_PROMISC_MULTICAST;
+ }
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_all_filter_hw_set(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+ struct sxe2_mac_filter *mac_entry;
+ struct sxe2_mac_filter *next_mac_entry;
+ struct sxe2_vlan_filter *vlan_entry;
+ struct sxe2_vlan_filter *next_vlan_entry;
+
+ if (adapter->filter_ctxt.uc_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.uc_list, next,
+ next_mac_entry) {
+ if (!mac_entry->hw_config) {
+ ret = sxe2_drv_uc_config(adapter, &mac_entry->mac_addr,
+ true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to add uc rule, ret:%d", ret);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ mac_entry->hw_config = true;
+ ret = 0;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.mc_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(mac_entry, &adapter->filter_ctxt.mc_list, next,
+ next_mac_entry) {
+ if (!mac_entry->hw_config) {
+ ret = sxe2_drv_mc_config(adapter, &mac_entry->mac_addr, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to add mc rule, ret:%d", ret);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ mac_entry->hw_config = true;
+ ret = 0;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.vlan_num > 0) {
+ RTE_TAILQ_FOREACH_SAFE(vlan_entry, &adapter->filter_ctxt.vlan_list, next,
+ next_vlan_entry) {
+ if (!vlan_entry->hw_config) {
+ ret = sxe2_drv_vlan_filter_id_config(adapter,
+ &vlan_entry->vlan_info, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to add vlan rule, ret:%d", ret);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ vlan_entry->hw_config = true;
+ ret = 0;
+ }
+ }
+ }
+
+ if (adapter->filter_ctxt.vlan_info.filter_on) {
+ if (!(adapter->filter_ctxt.vlan_info.hw_filter_on)) {
+ ret = sxe2_drv_vlan_filter_switch(adapter, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to add vlan ctrl, ret:%d", ret);
+ ret = -EINVAL;
+ goto l_end;
+ }
+ adapter->filter_ctxt.vlan_info.hw_filter_on = true;
+ ret = 0;
+ }
+ }
+
+ if ((adapter->filter_ctxt.cur_promisc_flags & SXE2_PROMISC) &&
+ (!(adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC))) {
+ ret = sxe2_drv_promisc_config(adapter, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to set promisc, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags |= SXE2_PROMISC;
+ ret = 0;
+ }
+
+ if ((adapter->filter_ctxt.cur_promisc_flags & SXE2_PROMISC_MULTICAST) &&
+ (!(adapter->filter_ctxt.hw_promisc_flags & SXE2_PROMISC_MULTICAST))) {
+ ret = sxe2_drv_allmulti_config(adapter, true);
+ if (ret && ret != -EEXIST) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to set allmulti, ret:%d", ret);
+ goto l_end;
+ }
+ adapter->filter_ctxt.hw_promisc_flags |= SXE2_PROMISC_MULTICAST;
+ ret = 0;
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter)
+{
+ int32_t ret = 0;
+
+ if (!adapter->flow_isolated && !adapter->switchdev_info.is_switchdev &&
+ adapter->rule_started) {
+ adapter->filter_ctxt.cur_l2_config = true;
+ } else {
+ adapter->filter_ctxt.cur_l2_config = false;
+ }
+
+ if (adapter->filter_ctxt.cur_l2_config !=
+ adapter->filter_ctxt.hw_l2_config) {
+ if (adapter->filter_ctxt.cur_l2_config) {
+ ret = sxe2_all_filter_hw_set(adapter);
+ if (!ret)
+ adapter->filter_ctxt.hw_l2_config = true;
+ } else {
+ ret = sxe2_all_filter_hw_clear(adapter);
+ if (!ret)
+ adapter->filter_ctxt.hw_l2_config = false;
+ }
+ }
+ return ret;
+}
+
+int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ adapter->rule_started = 0;
+
+ ret = sxe2_l2_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+ return ret;
+}
+
+int32_t sxe2_filter_rule_start(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ adapter->rule_started = 1;
+
+ ret = sxe2_l2_rule_update(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to update l2 rule");
+
+ return ret;
+}
+
+int32_t sxe2_filter_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ rte_spinlock_init(&adapter->filter_ctxt.filter_lock);
+
+ TAILQ_INIT(&adapter->filter_ctxt.uc_list);
+ adapter->filter_ctxt.uc_num = 0;
+
+ TAILQ_INIT(&adapter->filter_ctxt.mc_list);
+ adapter->filter_ctxt.mc_num = 0;
+
+ TAILQ_INIT(&adapter->filter_ctxt.vlan_list);
+ adapter->filter_ctxt.vlan_num = 0;
+ return 0;
+}
+
+int32_t sxe2_filter_uinit(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ sxe2_uc_filter_clear(adapter, true);
+ adapter->filter_ctxt.uc_num = 0;
+
+ sxe2_mc_filter_clear(adapter, true);
+ adapter->filter_ctxt.mc_num = 0;
+
+ sxe2_vlan_filters_clear(adapter, true);
+ adapter->filter_ctxt.vlan_num = 0;
+ return 0;
+}
diff --git a/drivers/net/sxe2/sxe2_filter.h b/drivers/net/sxe2/sxe2_filter.h
new file mode 100644
index 0000000000..6262e8c845
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_filter.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_FILTER_H__
+#define __SXE2_FILTER_H__
+#include <ethdev_driver.h>
+
+#define SXE2_PROMISC (1UL << 0UL)
+#define SXE2_PROMISC_MULTICAST (1UL << 1UL)
+
+struct sxe2_vlan_info {
+ uint8_t port_vlan_exist;
+ uint8_t is_switchdev;
+ uint16_t max_cnt;
+ uint16_t cnt;
+
+ bool filter_on;
+ bool hw_filter_on;
+
+ uint16_t tpid;
+ uint16_t vid;
+
+ uint8_t outer_insert;
+ uint8_t outer_strip;
+ uint8_t inner_insert;
+ uint8_t inner_strip;
+};
+
+struct sxe2_vlan {
+ uint16_t tpid;
+ uint16_t vid;
+ uint8_t prio;
+};
+
+struct sxe2_vlan_filter {
+ TAILQ_ENTRY(sxe2_vlan_filter) next;
+ bool hw_config;
+ bool default_config;
+ struct sxe2_vlan vlan_info;
+};
+
+TAILQ_HEAD(sxe2_vlan_filter_list_head, sxe2_vlan_filter);
+
+struct sxe2_mac_filter {
+ TAILQ_ENTRY(sxe2_mac_filter) next;
+ bool hw_config;
+ bool default_config;
+ struct rte_ether_addr mac_addr;
+};
+
+TAILQ_HEAD(sxe2_uc_filter_list_head, sxe2_mac_filter);
+TAILQ_HEAD(sxe2_mc_filter_list_head, sxe2_mac_filter);
+
+int32_t sxe2_uc_filter_add(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr, bool default_config);
+
+int32_t sxe2_uc_filter_del(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr);
+
+void sxe2_uc_filter_clear(struct sxe2_adapter *adapter, bool default_config);
+
+int32_t sxe2_mc_filter_add(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr, bool default_config);
+
+int32_t sxe2_mc_filter_del(struct sxe2_adapter *adapter,
+ struct rte_ether_addr *mac_addr);
+
+void sxe2_mc_filter_clear(struct sxe2_adapter *adapter, bool default_config);
+
+int32_t sxe2_vlan_filter_add(struct sxe2_adapter *adapter,
+ struct sxe2_vlan *vlan, bool default_config);
+
+int32_t sxe2_vlan_filter_del(struct sxe2_adapter *adapter, struct sxe2_vlan *vlan);
+
+void sxe2_vlan_filters_clear(struct sxe2_adapter *adapter, bool default_config);
+
+int32_t sxe2_vlan_filter_ctrl(struct sxe2_adapter *adapter, bool flag);
+
+int32_t sxe2_promisc_add(struct sxe2_adapter *adapter);
+
+int32_t sxe2_promisc_del(struct sxe2_adapter *adapter);
+
+int32_t sxe2_allmulti_add(struct sxe2_adapter *adapter);
+
+int32_t sxe2_allmulti_del(struct sxe2_adapter *adapter);
+
+int32_t sxe2_l2_rule_update(struct sxe2_adapter *adapter);
+
+int32_t sxe2_filter_rule_stop(struct rte_eth_dev *dev);
+
+int32_t sxe2_filter_rule_start(struct rte_eth_dev *dev);
+
+int32_t sxe2_filter_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_filter_uinit(struct rte_eth_dev *dev);
+
+#endif /* __SXE2_FILTER_H__ */
diff --git a/drivers/net/sxe2/sxe2_mac.c b/drivers/net/sxe2/sxe2_mac.c
index 3c2f909002..d94936a742 100644
--- a/drivers/net/sxe2/sxe2_mac.c
+++ b/drivers/net/sxe2/sxe2_mac.c
@@ -10,6 +10,438 @@
#include "sxe2_cmd_chnl.h"
#include "sxe2_host_regs.h"
+int32_t sxe2_mac_default_cfg(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret;
+ struct rte_ether_addr broadcast = {
+ .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
+ struct rte_ether_addr mac_addr;
+
+ rte_ether_addr_copy((struct rte_ether_addr *)
+ adapter->dev_info.mac.perm_addr, &mac_addr);
+ ret = sxe2_uc_filter_add(adapter, &mac_addr, true);
+ if (ret != 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add default MAC filter");
+ goto l_end;
+ }
+
+ rte_ether_addr_copy(&broadcast, &mac_addr);
+ ret = sxe2_mc_filter_add(adapter, &mac_addr, true);
+ if (ret != 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add broadcast MAC filter");
+ goto l_end;
+ }
+
+ ret = 0;
+l_end:
+ return ret;
+}
+
+int32_t sxe2_mac_addr_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = -1;
+ PMD_INIT_FUNC_TRACE();
+
+ if (!rte_is_unicast_ether_addr
+ ((struct rte_ether_addr *)adapter->dev_info.mac.perm_addr)) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Invalid MAC address");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ dev->data->mac_addrs = rte_zmalloc("sxe2_mac_adds",
+ sizeof(struct rte_ether_addr) * SXE2_NUM_MACADDR_MAX, 0);
+ if (!dev->data->mac_addrs) {
+ PMD_LOG_ERR(DRV, "Failed to allocate memory to store mac address");
+ ret = -ENOMEM;
+ goto l_end;
+ }
+
+ rte_ether_addr_copy((struct rte_ether_addr *)adapter->dev_info.mac.perm_addr,
+ &dev->data->mac_addrs[0]);
+
+ ret = 0;
+
+l_end:
+ return ret;
+}
+
+void sxe2_mac_addr_uinit(struct rte_eth_dev *dev)
+{
+ PMD_INIT_FUNC_TRACE();
+ if (dev != NULL && dev->data->mac_addrs != NULL) {
+ rte_free(dev->data->mac_addrs);
+ dev->data->mac_addrs = NULL;
+ }
+}
+
+int32_t sxe2_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t index, __rte_unused uint32_t pool)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = -1;
+
+ if (rte_is_zero_ether_addr(mac_addr)) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Invalid MAC Address");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = sxe2_mc_filter_add(adapter, mac_addr, true);
+ else
+ ret = sxe2_uc_filter_add(adapter, mac_addr, false);
+
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add MAC filter");
+
+l_end:
+ return ret;
+}
+
+void sxe2_mac_addr_del(struct rte_eth_dev *dev, uint32_t index)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct rte_ether_addr *mac_addr = &dev->data->mac_addrs[index];
+ int32_t ret = -1;
+
+ if (rte_is_multicast_ether_addr(mac_addr))
+ ret = sxe2_mc_filter_del(adapter, mac_addr);
+ else
+ ret = sxe2_uc_filter_del(adapter, mac_addr);
+
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to remove MAC filter");
+}
+
+int32_t sxe2_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ struct rte_ether_addr *old_addr = (struct rte_ether_addr *)&adapter->dev_info.mac.perm_addr;
+ struct rte_ether_addr temp_addr;
+
+ if (rte_is_same_ether_addr(old_addr, mac_addr))
+ goto l_end;
+
+ if (rte_is_multicast_ether_addr(mac_addr)) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to set multicast addr");
+ ret = -EINVAL;
+ goto l_end;
+ }
+
+ ret = sxe2_uc_filter_del(adapter, old_addr);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to remove MAC filter");
+ goto l_end;
+ }
+
+ rte_ether_addr_copy(old_addr, &temp_addr);
+
+ rte_ether_addr_copy(mac_addr, old_addr);
+
+ ret = sxe2_uc_filter_add(adapter, mac_addr, true);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add MAC filter");
+ rte_ether_addr_copy(&temp_addr, old_addr);
+ (void)sxe2_uc_filter_add(adapter, old_addr, true);
+ goto l_end;
+ }
+l_end:
+ return ret;
+}
+
+int32_t sxe2_set_mc_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addrs,
+ uint32_t mc_addrs_num)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ uint32_t i;
+ const uint8_t *mac;
+
+ if (mc_addrs_num > SXE2_NUM_MACADDR_MAX) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Too many multicast MAC addresses, ");
+ ret = -1;
+ goto l_end;
+ }
+
+ sxe2_mc_filter_clear(adapter, false);
+
+ for (i = 0; i < mc_addrs_num; i++) {
+ if (!rte_is_multicast_ether_addr(&mc_addrs[i])) {
+ mac = mc_addrs[i].addr_bytes;
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Invalid mac: %02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4],
+ mac[5]);
+ ret = -EINVAL;
+ goto add_err;
+ }
+
+ ret = sxe2_mc_filter_add(adapter, &mc_addrs[i], false);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Failed to remove old multicast MAC filter list");
+ goto add_err;
+ }
+ }
+ goto l_end;
+add_err:
+ sxe2_mc_filter_clear(adapter, false);
+l_end:
+ return ret;
+}
+
+int32_t sxe2_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int32_t on)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ struct sxe2_vlan vlan = {
+ .tpid = RTE_ETHER_TYPE_VLAN,
+ .vid = vlan_id,
+ .prio = 0
+ };
+ int32_t ret = 0;
+
+ if (sxe2_dev_port_vlan_check(dev)) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Filter not supported with Port VLAN");
+ ret = -ENOTSUP;
+ goto l_end;
+ }
+
+ if (vlan_id == 0)
+ goto l_end;
+
+ if (on) {
+ ret = sxe2_vlan_filter_add(adapter, &vlan, false);
+ if (ret < 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add vlan filter");
+ goto l_end;
+ }
+ } else {
+ ret = sxe2_vlan_filter_del(adapter, &vlan);
+ if (ret < 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to remove vlan filter");
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_dev_vlan_offload_set(struct rte_eth_dev *dev, int32_t mask)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+ struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+ struct rte_eth_txmode *txmode = &dev->data->dev_conf.txmode;
+ struct sxe2_vlan_info new_info = adapter->filter_ctxt.vlan_info;
+ bool port_vlan = new_info.port_vlan_exist;
+
+ uint8_t out_strip_mask = SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021Q |
+ SXE2_DPDK_OFFLOAD_OUTER_STRIP_8021AD |
+ SXE2_DPDK_OFFLOAD_OUTER_STRIP_QINQ1;
+
+ if (txmode->offloads & RTE_ETH_TX_OFFLOAD_QINQ_INSERT) {
+ if (!(txmode->offloads & RTE_ETH_TX_OFFLOAD_VLAN_INSERT)) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "VLAN INSERT must be enabled when QinQ INSERT is enabled");
+ return -EINVAL;
+ }
+ if (port_vlan) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "QINQ INSERT not supported with Port VLAN");
+ return -EINVAL;
+ }
+ }
+
+ if (mask & RTE_ETH_QINQ_STRIP_MASK) {
+ if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_QINQ_STRIP) {
+ if (port_vlan) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "QinQ strip not supported with Port VLAN");
+ return -EINVAL;
+ }
+ new_info.inner_strip = SXE2_VSI_TSR_ID_VLAN;
+ } else {
+ new_info.inner_strip = 0;
+ }
+ }
+
+ if (mask & RTE_ETH_VLAN_STRIP_MASK) {
+ if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP) {
+ new_info.outer_strip =
+ port_vlan ? 0 : out_strip_mask;
+ new_info.inner_strip =
+ port_vlan ? new_info.inner_strip : new_info.inner_strip;
+ } else {
+ if (new_info.inner_strip != 0) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "Must disable QinQ strip before disabling VLAN strip");
+ return -EINVAL;
+ }
+ new_info.outer_strip = 0;
+ }
+ }
+
+ if (mask & (RTE_ETH_VLAN_STRIP_MASK | RTE_ETH_QINQ_STRIP_MASK)) {
+ struct sxe2_vlan_info old_info = adapter->filter_ctxt.vlan_info;
+ adapter->filter_ctxt.vlan_info = new_info;
+
+ ret = sxe2_drv_vlan_insert_strip_cfg(adapter);
+ if (ret) {
+ adapter->filter_ctxt.vlan_info = old_info;
+ return ret;
+ }
+ }
+ if (mask & RTE_ETH_VLAN_FILTER_MASK) {
+ if (adapter->filter_ctxt.vlan_info.port_vlan_exist) {
+ ret = 0;
+ PMD_DEV_LOG_INFO(adapter, INIT, "vlan filter is not support when port vlan is enabled");
+ goto l_end;
+ }
+
+ ret = sxe2_vlan_filter_ctrl(adapter,
+ !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_FILTER));
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV,
+ "sxe2_drv_vlan_filter_switch failed ret:%d", ret);
+ goto l_end;
+ }
+ }
+
+ PMD_DEV_LOG_DEBUG(adapter, DRV,
+ "mask:0x%x rx mode offload:0x%" PRIx64 " vlan offload set done",
+ mask, rxmode->offloads);
+l_end:
+ return ret;
+}
+
+static int32_t sxe2_vlan_filter_zero(struct sxe2_adapter *adapter)
+{
+ struct sxe2_vlan vlan;
+ int32_t ret;
+ uint16_t tpids[] = {RTE_ETHER_TYPE_VLAN, RTE_ETHER_TYPE_QINQ, RTE_ETHER_TYPE_QINQ1};
+ uint8_t i;
+
+ vlan = (struct sxe2_vlan){0, 0, 0};
+ ret = sxe2_vlan_filter_add(adapter, &vlan, true);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add VLAN ID 0");
+ goto l_end;
+ }
+
+ for (i = 0; i < RTE_DIM(tpids); i++) {
+ vlan = (struct sxe2_vlan){tpids[i], 0, 0};
+ ret = sxe2_vlan_filter_add(adapter, &vlan, true);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add VLAN ID 0 when tpid:0x%x",
+ tpids[i]);
+ goto l_end;
+ }
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_vlan_cfg_init(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ ret = sxe2_drv_vlan_config_query(adapter);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to query vlan config, ret=%d", ret);
+ goto l_end;
+ }
+
+ if (!sxe2_dev_port_vlan_check(dev))
+ adapter->filter_ctxt.vlan_info.outer_insert =
+ SXE2_DPDK_OFFLOAD_OUTER_INSERT_8021Q |
+ SXE2_DPDK_OFFLOAD_INSERT_ENABLE;
+ else
+ adapter->filter_ctxt.vlan_info.outer_insert = 0;
+
+ adapter->filter_ctxt.vlan_info.inner_insert =
+ SXE2_DPDK_OFFLOAD_INNER_INSERT_QINQ1 | SXE2_DPDK_OFFLOAD_INSERT_ENABLE;
+
+ if (!sxe2_dev_port_vlan_check(dev)) {
+ ret = sxe2_vlan_filter_zero(adapter);
+ if (ret != 0)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to add vlan filter switch:0 "
+ "for port:%d", adapter->port_idx);
+ }
+
+l_end:
+ return ret;
+}
+
+int32_t sxe2_vlan_default_cfg(struct rte_eth_dev *dev)
+{
+ int32_t ret = 0;
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+
+ ret = sxe2_dev_vlan_offload_set(dev, RTE_ETH_VLAN_STRIP_MASK |
+ RTE_ETH_QINQ_STRIP_MASK |
+ RTE_ETH_VLAN_FILTER_MASK);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to cfg vlan offload, ret:%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_promisc_enable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ ret = sxe2_promisc_add(adapter);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to enable promisc, ret:%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_promisc_disable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ ret = sxe2_promisc_del(adapter);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to disable promisc, ret:%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_allmulti_enable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ ret = sxe2_allmulti_add(adapter);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to enable allmulti, ret:%d", ret);
+
+ return ret;
+}
+
+int32_t sxe2_allmulti_disable(struct rte_eth_dev *dev)
+{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
+ int32_t ret = 0;
+
+ ret = sxe2_allmulti_del(adapter);
+ if (ret)
+ PMD_DEV_LOG_ERR(adapter, DRV, "Failed to disable allmulti, ret:%d", ret);
+
+ return ret;
+}
+
int32_t sxe2_link_update_init(struct rte_eth_dev *dev)
{
struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
diff --git a/drivers/net/sxe2/sxe2_mac.h b/drivers/net/sxe2/sxe2_mac.h
index f2f3edaeff..55fd1829a0 100644
--- a/drivers/net/sxe2/sxe2_mac.h
+++ b/drivers/net/sxe2/sxe2_mac.h
@@ -43,6 +43,40 @@ struct sxe2_mac_mc_list {
int32_t sxe2_link_update_init(struct rte_eth_dev *dev);
+int32_t sxe2_mac_default_cfg(struct rte_eth_dev *dev);
+
+int32_t sxe2_vlan_cfg_init(struct rte_eth_dev *dev);
+
+int32_t sxe2_mac_addr_init(struct rte_eth_dev *dev);
+
+void sxe2_mac_addr_uinit(struct rte_eth_dev *dev);
+
+int32_t sxe2_mac_addr_add(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mac_addr,
+ __rte_unused uint32_t index, __rte_unused uint32_t pool);
+
+void sxe2_mac_addr_del(struct rte_eth_dev *dev, uint32_t index);
+
+int32_t sxe2_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr);
+
+int32_t sxe2_set_mc_addr_list(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mc_addrs,
+ uint32_t mc_addrs_num);
+
+int32_t sxe2_promisc_enable(struct rte_eth_dev *dev);
+
+int32_t sxe2_promisc_disable(struct rte_eth_dev *dev);
+
+int32_t sxe2_allmulti_enable(struct rte_eth_dev *dev);
+
+int32_t sxe2_allmulti_disable(struct rte_eth_dev *dev);
+
+int32_t sxe2_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int32_t on);
+
+int32_t sxe2_dev_vlan_offload_set(struct rte_eth_dev *dev, int32_t mask);
+
+int32_t sxe2_vlan_default_cfg(struct rte_eth_dev *dev);
+
int32_t sxe2_link_update(struct rte_eth_dev *dev, __rte_unused int32_t wait_to_complete);
int32_t sxe2_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
diff --git a/drivers/net/sxe2/sxe2_txrx_poll.c b/drivers/net/sxe2/sxe2_txrx_poll.c
index b9d34afb31..21d5c38725 100644
--- a/drivers/net/sxe2/sxe2_txrx_poll.c
+++ b/drivers/net/sxe2/sxe2_txrx_poll.c
@@ -660,6 +660,53 @@ sxe2_rx_desc_error_para(__rte_unused struct sxe2_rx_queue *rxq,
return flags;
}
+static inline void sxe2_rx_desc_vlan_para_fill(struct rte_mbuf *mbuf,
+ union sxe2_rx_desc *desc)
+{
+ if (0 == (rte_le_to_cpu_64(desc->wb.status_err_ptype_len) &
+ SXE2_RX_DESC_STATUS_L2TAG1_P_MASK)) {
+ mbuf->vlan_tci = 0;
+ } else {
+ mbuf->ol_flags |= (RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED);
+ mbuf->vlan_tci = rte_le_to_cpu_16(desc->wb.l2tag1);
+ PMD_LOG_DEBUG(RX, "Rx desc mbuf vlan, vlan_tci:%u",
+ mbuf->vlan_tci);
+ }
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+ if (0 == (rte_le_to_cpu_32(desc->wb.status_lrocnt_fdpf_id) &
+ SXE2_RX_DESC_EXT_STATUS_L2TAG2P_MASK)) {
+ mbuf->vlan_tci_outer = 0;
+ } else {
+ mbuf->ol_flags |= RTE_MBUF_F_RX_QINQ_STRIPPED | RTE_MBUF_F_RX_QINQ |
+ RTE_MBUF_F_RX_VLAN_STRIPPED | RTE_MBUF_F_RX_VLAN;
+ mbuf->vlan_tci_outer = mbuf->vlan_tci;
+ mbuf->vlan_tci = rte_le_to_cpu_16(desc->wb.l2tag2_2nd);
+ PMD_LOG_DEBUG(RX, "Rx desc out vlan, l2tag2_1st:%u l2tag2_2nd:%u.",
+ rte_le_to_cpu_16(desc->wb.l2tag2_1st),
+ rte_le_to_cpu_16(desc->wb.l2tag2_2nd));
+ }
+#endif
+}
+
+static inline void
+sxe2_rx_desc_filter_para_fill(struct sxe2_rx_queue *rxq __rte_unused,
+ struct rte_mbuf *mbuf, union sxe2_rx_desc *desc)
+{
+ if (SXE2_RX_DESC_STATUS_RSS_VLD_MASK &
+ rte_le_to_cpu_64(desc->wb.status_err_ptype_len)) {
+ mbuf->ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
+ mbuf->hash.rss = rte_le_to_cpu_32(desc->wb.filter_status);
+ PMD_LOG_DEBUG(RX, "rss id:%u", mbuf->hash.rss);
+ }
+#ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC
+ if (SXE2_RX_DESC_FD_VLD_MASK & desc->wb.rxdid_src) {
+ mbuf->ol_flags |= (RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID);
+ mbuf->hash.fdir.hi = rte_le_to_cpu_32(desc->wb.fd_filter_id);
+ PMD_LOG_DEBUG(RX, "fdir id:%u", mbuf->hash.fdir.hi);
+ }
+#endif
+}
+
static __rte_always_inline void
sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, struct rte_mbuf *mbuf,
union sxe2_rx_desc *rxd)
@@ -673,6 +720,8 @@ sxe2_rx_mbuf_common_fields_fill(struct sxe2_rx_queue *rxq, struct rte_mbuf *mbuf
mbuf->packet_type = ptype_tbl[SXE2_RX_DESC_PTYPE_VAL_GET(qword1)];
pkt_flags = sxe2_rx_desc_error_para(rxq, rxd);
+ sxe2_rx_desc_vlan_para_fill(mbuf, rxd);
+ sxe2_rx_desc_filter_para_fill(rxq, mbuf, rxd);
mbuf->ol_flags |= pkt_flags;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v14 18/20] net/sxe2: add mbuf validation in Tx debug mode
From: liujie5 @ 2026-06-09 1:39 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260609013951.3359199-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
Introduce the `sxe2_txrx_check_mbuf` helper function to validate outgoing
mbufs when `RTE_ETHDEV_DEBUG_TX` is enabled. This helps developers catch
malformed mbufs (e.g., invalid segment lengths, bad offload flags, or
unaligned buffers) before passing them to the hardware rings, avoiding
potential hardware hangs or silent packet drops.
The validation is fully wrapped inside `RTE_ETHDEV_DEBUG_TX` conditional
compilation blocks to ensure zero performance overhead in standard
production builds.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
drivers/net/sxe2/meson.build | 2 +
drivers/net/sxe2/sxe2_txrx.c | 8 +-
drivers/net/sxe2/sxe2_txrx_check_mbuf.c | 595 ++++++++++++++++++++++++
drivers/net/sxe2/sxe2_txrx_check_mbuf.h | 38 ++
4 files changed, 641 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.c
create mode 100644 drivers/net/sxe2/sxe2_txrx_check_mbuf.h
diff --git a/drivers/net/sxe2/meson.build b/drivers/net/sxe2/meson.build
index d653d071a9..4fb2333926 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -78,4 +78,6 @@ sources += files(
'sxe2_flow_parse_pattern.c',
'sxe2_flow_parse_engine.c',
'sxe2_dump.c',
+ 'sxe2_txrx_check_mbuf.c',
+
)
diff --git a/drivers/net/sxe2/sxe2_txrx.c b/drivers/net/sxe2/sxe2_txrx.c
index 3861e31688..630353461d 100644
--- a/drivers/net/sxe2/sxe2_txrx.c
+++ b/drivers/net/sxe2/sxe2_txrx.c
@@ -13,6 +13,7 @@
#include "sxe2_txrx_common.h"
#include "sxe2_txrx_vec.h"
#include "sxe2_txrx_poll.h"
+#include "sxe2_txrx_check_mbuf.h"
#include "sxe2_ethdev.h"
#include "sxe2_common_log.h"
#include "sxe2_osal.h"
@@ -120,13 +121,11 @@ uint16_t sxe2_tx_pkts_prepare(void *tx_queue,
rte_errno = -EINVAL;
goto l_end;
}
-#ifdef RTE_ETHDEV_DEBUG_TX
ret = rte_validate_tx_offload(mbuf);
if (ret != 0) {
rte_errno = -ret;
goto l_end;
}
-#endif
ret = rte_net_intel_cksum_prepare(mbuf);
if (ret != 0) {
rte_errno = -ret;
@@ -137,6 +136,11 @@ uint16_t sxe2_tx_pkts_prepare(void *tx_queue,
rte_errno = -ret;
goto l_end;
}
+ ret = sxe2_txrx_check_mbuf(mbuf);
+ if (ret != 0) {
+ rte_errno = -ret;
+ goto l_end;
+ }
}
l_end:
return i;
diff --git a/drivers/net/sxe2/sxe2_txrx_check_mbuf.c b/drivers/net/sxe2/sxe2_txrx_check_mbuf.c
new file mode 100644
index 0000000000..7d316ae652
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_check_mbuf.c
@@ -0,0 +1,595 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#include <rte_common.h>
+#include <rte_net.h>
+#include <rte_vect.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <ethdev_driver.h>
+#include <rte_geneve.h>
+
+#include "sxe2_txrx_check_mbuf.h"
+#include "sxe2_common_log.h"
+
+#define TX_IPPROTO_IPIP 4
+#define TX_IPPROTO_GRE 47
+#define GRE_CHECKSUM_PRESENT 0x8000
+#define GRE_KEY_PRESENT 0x2000
+#define GRE_SEQUENCE_PRESENT 0x1000
+#define GRE_EXT_LEN 4
+#define GRE_SUPPORTED_FIELDS (GRE_CHECKSUM_PRESENT | GRE_KEY_PRESENT | GRE_SEQUENCE_PRESENT)
+
+
+static uint16_t vxlan_gpe_udp_port = RTE_VXLAN_GPE_DEFAULT_PORT;
+static uint16_t geneve_udp_port = RTE_GENEVE_DEFAULT_PORT;
+
+static inline int32_t check_mbuf_len(struct offload_info *info, struct rte_mbuf *m)
+{
+ int32_t ret = 0;
+ if (m->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+ if (info->outer_l2_len != m->outer_l2_len) {
+ PMD_LOG_ERR(TX, "outer_l2_len error in mbuf. Original "
+ "length:%u calculated length:%u", m->outer_l2_len,
+ info->outer_l2_len);
+ ret = -1;
+ goto end;
+ }
+ if (info->outer_l3_len != m->outer_l3_len) {
+ PMD_LOG_ERR(TX, "outer_l3_len error in mbuf. Original "
+ "length:%u calculated length:%u", m->outer_l3_len,
+ info->outer_l3_len);
+ ret = -1;
+ goto end;
+ }
+ }
+
+ if (info->l2_len != m->l2_len) {
+ PMD_LOG_ERR(TX, "l2_len error in mbuf. Original "
+ "length:%u calculated length:%u", m->l2_len, info->l2_len);
+ ret = -1;
+ goto end;
+ }
+ if (info->l3_len != m->l3_len) {
+ PMD_LOG_ERR(TX, "l3_len error in mbuf. Original "
+ "length:%u calculated length:%u", m->l3_len, info->l3_len);
+ ret = -1;
+ goto end;
+ }
+ if (info->l4_len != m->l4_len) {
+ PMD_LOG_ERR(TX, "l4_len error in mbuf. Original "
+ "length:%u calculated length:%u", m->l4_len, info->l4_len);
+ ret = -1;
+ goto end;
+ }
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static inline int32_t check_ether_type(struct offload_info *info, struct rte_mbuf *m)
+{
+ int32_t ret = 0;
+
+ if (m->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+ if (info->outer_ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+ if (!(m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)) {
+ PMD_LOG_ERR(TX, "Outer ethernet type is ipv4, "
+ "tx offload missing `RTE_MBUF_F_TX_OUTER_IPV4` flag");
+ ret = -1;
+ goto end;
+ }
+ if (m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV6) {
+ PMD_LOG_ERR(TX, "Outer ethernet type is ipv4, tx "
+ "offload contains wrong `RTE_MBUF_F_TX_OUTER_IPV6` flag");
+ ret = -1;
+ goto end;
+ }
+ } else if (info->outer_ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+ if (!(m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)) {
+ PMD_LOG_ERR(TX, "Outer ethernet type is ipv6, "
+ "tx offload missing `RTE_MBUF_F_TX_OUTER_IPV6` flag");
+ ret = -1;
+ goto end;
+ }
+ if (m->ol_flags & RTE_MBUF_F_TX_OUTER_IPV4) {
+ PMD_LOG_ERR(TX, "Outer ethernet type is ipv6, tx "
+ "offload contains wrong `RTE_MBUF_F_TX_OUTER_IPV4` flag");
+ ret = -1;
+ goto end;
+ }
+ }
+ }
+
+ if (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+ if (!(m->ol_flags & RTE_MBUF_F_TX_IPV4)) {
+ PMD_LOG_ERR(TX, "Ethernet type is ipv4, tx offload "
+ "missing `RTE_MBUF_F_TX_IPV4` flag.");
+ ret = -1;
+ goto end;
+ }
+ if (m->ol_flags & RTE_MBUF_F_TX_IPV6) {
+ PMD_LOG_ERR(TX, "Ethernet type is ipv4, tx "
+ "offload contains wrong `RTE_MBUF_F_TX_IPV6` flag");
+ ret = -1;
+ goto end;
+ }
+ } else if (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+ if (!(m->ol_flags & RTE_MBUF_F_TX_IPV6)) {
+ PMD_LOG_ERR(TX, "Ethernet type is ipv6, tx offload "
+ "missing `RTE_MBUF_F_TX_IPV6` flag.");
+ ret = -1;
+ goto end;
+ }
+ if (m->ol_flags & RTE_MBUF_F_TX_IPV4) {
+ PMD_LOG_ERR(TX, "Ethernet type is ipv6, tx offload "
+ "contains wrong `RTE_MBUF_F_TX_IPV4` flag");
+ ret = -1;
+ goto end;
+ }
+ }
+ ret = 0;
+
+end:
+ return ret;
+}
+
+static inline void parse_ipv4(struct rte_ipv4_hdr *ipv4_hdr, struct offload_info *info)
+{
+ struct rte_tcp_hdr *tcp_hdr;
+
+ info->l3_len = rte_ipv4_hdr_len(ipv4_hdr);
+ info->l4_proto = ipv4_hdr->next_proto_id;
+
+ if (info->l4_proto == IPPROTO_TCP) {
+ tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv4_hdr + info->l3_len);
+ info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+ } else if (info->l4_proto == IPPROTO_UDP) {
+ info->l4_len = sizeof(struct rte_udp_hdr);
+ } else {
+ info->l4_len = 0;
+ }
+}
+
+static inline void parse_ipv6(struct rte_ipv6_hdr *ipv6_hdr, struct offload_info *info)
+{
+ struct rte_tcp_hdr *tcp_hdr;
+
+ info->l3_len = sizeof(struct rte_ipv6_hdr);
+ info->l4_proto = ipv6_hdr->proto;
+
+ if (info->l4_proto == IPPROTO_TCP) {
+ tcp_hdr = (struct rte_tcp_hdr *)((char *)ipv6_hdr + info->l3_len);
+ info->l4_len = (tcp_hdr->data_off & 0xf0) >> 2;
+ } else if (info->l4_proto == IPPROTO_UDP) {
+ info->l4_len = sizeof(struct rte_udp_hdr);
+ } else {
+ info->l4_len = 0;
+ }
+}
+
+static inline void parse_ethernet(struct rte_ether_hdr *eth_hdr, struct offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_vlan_hdr *vlan_hdr;
+
+ info->l2_len = sizeof(struct rte_ether_hdr);
+ info->ethertype = eth_hdr->ether_type;
+
+ while (info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN) ||
+ info->ethertype == rte_cpu_to_be_16(RTE_ETHER_TYPE_QINQ)) {
+ vlan_hdr = (struct rte_vlan_hdr *)
+ ((char *)eth_hdr + info->l2_len);
+ info->l2_len += sizeof(struct rte_vlan_hdr);
+ info->ethertype = vlan_hdr->eth_proto;
+ }
+
+ switch (info->ethertype) {
+ case RTE_STATIC_BSWAP16(RTE_ETHER_TYPE_IPV4):
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)eth_hdr + info->l2_len);
+ parse_ipv4(ipv4_hdr, info);
+ break;
+ case RTE_STATIC_BSWAP16(RTE_ETHER_TYPE_IPV6):
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)eth_hdr + info->l2_len);
+ parse_ipv6(ipv6_hdr, info);
+ break;
+ default:
+ info->l4_len = 0;
+ info->l3_len = 0;
+ info->l4_proto = 0;
+ break;
+ }
+}
+
+static inline void update_tunnel_outer(struct offload_info *info)
+{
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+ info->outer_l4_proto = info->l4_proto;
+}
+
+static inline void parse_gtp(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_gtp_hdr *gtp_hdr;
+ uint8_t gtp_len = sizeof(*gtp_hdr);
+ uint8_t ip_ver;
+
+ if (udp_hdr->dst_port != rte_cpu_to_be_16(RTE_GTPC_UDP_PORT) &&
+ udp_hdr->src_port != rte_cpu_to_be_16(RTE_GTPC_UDP_PORT) &&
+ udp_hdr->dst_port != rte_cpu_to_be_16(RTE_GTPU_UDP_PORT))
+ goto end;
+
+ update_tunnel_outer(info);
+ info->l2_len = 0;
+
+ gtp_hdr = (struct rte_gtp_hdr *)((char *)udp_hdr + sizeof(*udp_hdr));
+
+ if (gtp_hdr->msg_type == 0xff) {
+ ip_ver = *(uint8_t *)((char *)udp_hdr + sizeof(*udp_hdr) + sizeof(*gtp_hdr));
+ ip_ver = (ip_ver) & 0xf0;
+
+ if (ip_ver == RTE_GTP_TYPE_IPV4) {
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gtp_hdr + gtp_len);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ parse_ipv4(ipv4_hdr, info);
+ } else if (ip_ver == RTE_GTP_TYPE_IPV6) {
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gtp_hdr + gtp_len);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ }
+ } else {
+ info->ethertype = 0;
+ info->l4_len = 0;
+ info->l3_len = 0;
+ info->l4_proto = 0;
+ }
+
+ info->l2_len += RTE_ETHER_GTP_HLEN;
+
+end:
+ return;
+}
+
+static inline void parse_vxlan(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+
+ if (udp_hdr->dst_port != rte_cpu_to_be_16(RTE_VXLAN_DEFAULT_PORT))
+ goto end;
+
+ update_tunnel_outer(info);
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)udp_hdr +
+ sizeof(struct rte_udp_hdr) + sizeof(struct rte_vxlan_hdr));
+
+ parse_ethernet(eth_hdr, info);
+ info->l2_len += RTE_ETHER_VXLAN_HLEN;
+
+end:
+ return;
+}
+
+static inline void parse_vxlan_gpe(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_vxlan_gpe_hdr *vxlan_gpe_hdr;
+ uint8_t vxlan_gpe_len = sizeof(*vxlan_gpe_hdr);
+
+ if (udp_hdr->dst_port != rte_cpu_to_be_16(vxlan_gpe_udp_port))
+ goto end;
+
+ vxlan_gpe_hdr = (struct rte_vxlan_gpe_hdr *)((char *)udp_hdr + sizeof(struct rte_udp_hdr));
+
+ if (!vxlan_gpe_hdr->proto || vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_IPV4) {
+ update_tunnel_outer(info);
+
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ info->l2_len = 0;
+
+ } else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_IPV6) {
+ update_tunnel_outer(info);
+
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ info->l2_len = 0;
+
+ } else if (vxlan_gpe_hdr->proto == RTE_VXLAN_GPE_TYPE_ETH) {
+ update_tunnel_outer(info);
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)vxlan_gpe_hdr + vxlan_gpe_len);
+
+ parse_ethernet(eth_hdr, info);
+ } else {
+ goto end;
+ }
+
+ info->l2_len += RTE_ETHER_VXLAN_GPE_HLEN;
+
+end:
+ return;
+}
+
+static inline void parse_geneve(struct rte_udp_hdr *udp_hdr, struct offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ struct rte_geneve_hdr *geneve_hdr;
+ uint16_t geneve_len;
+
+ if (udp_hdr->dst_port != rte_cpu_to_be_16(geneve_udp_port))
+ goto end;
+
+ geneve_hdr = (struct rte_geneve_hdr *)((char *)udp_hdr + sizeof(struct rte_udp_hdr));
+ geneve_len = sizeof(struct rte_geneve_hdr) + geneve_hdr->opt_len * 4;
+ if (!geneve_hdr->proto || geneve_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+ update_tunnel_outer(info);
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)geneve_hdr + geneve_len);
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ info->l2_len = 0;
+ } else if (geneve_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+ update_tunnel_outer(info);
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)geneve_hdr + geneve_len);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ info->l2_len = 0;
+
+ } else if (geneve_hdr->proto == rte_cpu_to_be_16(RTE_GENEVE_TYPE_ETH)) {
+ update_tunnel_outer(info);
+ eth_hdr = (struct rte_ether_hdr *)((char *)geneve_hdr + geneve_len);
+ parse_ethernet(eth_hdr, info);
+ } else {
+ goto end;
+ }
+
+ info->l2_len += (sizeof(struct rte_udp_hdr) + sizeof(struct rte_geneve_hdr) +
+ ((struct rte_geneve_hdr *)geneve_hdr)->opt_len * 4);
+
+end:
+ return;
+}
+
+static inline void parse_gre(struct simple_gre_hdr *gre_hdr, struct offload_info *info)
+{
+ struct rte_ether_hdr *eth_hdr;
+ struct rte_ipv4_hdr *ipv4_hdr;
+ struct rte_ipv6_hdr *ipv6_hdr;
+ uint8_t gre_len = 0;
+
+ gre_len += sizeof(struct simple_gre_hdr);
+
+ if (gre_hdr->flags & rte_cpu_to_be_16(GRE_KEY_PRESENT))
+ gre_len += GRE_EXT_LEN;
+ if (gre_hdr->flags & rte_cpu_to_be_16(GRE_SEQUENCE_PRESENT))
+ gre_len += GRE_EXT_LEN;
+ if (gre_hdr->flags & rte_cpu_to_be_16(GRE_CHECKSUM_PRESENT))
+ gre_len += GRE_EXT_LEN;
+
+ if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
+ update_tunnel_outer(info);
+
+ ipv4_hdr = (struct rte_ipv4_hdr *)((char *)gre_hdr + gre_len);
+
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ info->l2_len = 0;
+
+ } else if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
+ update_tunnel_outer(info);
+
+ ipv6_hdr = (struct rte_ipv6_hdr *)((char *)gre_hdr + gre_len);
+
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ parse_ipv6(ipv6_hdr, info);
+ info->l2_len = 0;
+
+ } else if (gre_hdr->proto == rte_cpu_to_be_16(RTE_ETHER_TYPE_TEB)) {
+ update_tunnel_outer(info);
+
+ eth_hdr = (struct rte_ether_hdr *)((char *)gre_hdr + gre_len);
+
+ parse_ethernet(eth_hdr, info);
+ } else {
+ goto end;
+ }
+
+ info->l2_len += gre_len;
+
+end:
+ return;
+}
+
+static inline void parse_encap_ip(void *encap_ip, struct offload_info *info)
+{
+ struct rte_ipv4_hdr *ipv4_hdr = encap_ip;
+ struct rte_ipv6_hdr *ipv6_hdr = encap_ip;
+ uint8_t ip_version;
+
+ ip_version = ((ipv4_hdr->version_ihl & 0xf0) >> 4);
+
+ if (ip_version != 4 && ip_version != 6)
+ goto end;
+
+ info->is_tunnel = 1;
+ info->outer_ethertype = info->ethertype;
+ info->outer_l2_len = info->l2_len;
+ info->outer_l3_len = info->l3_len;
+
+ if (ip_version == 4) {
+ parse_ipv4(ipv4_hdr, info);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
+ } else {
+ parse_ipv6(ipv6_hdr, info);
+ info->ethertype = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
+ }
+ info->l2_len = 0;
+
+end:
+ return;
+}
+
+__rte_unused int32_t sxe2_txrx_check_mbuf(struct rte_mbuf *m)
+{
+ int32_t ret = 0;
+ struct rte_ether_hdr *eth_hdr;
+ void *l3_hdr = NULL;
+ struct offload_info info = {0};
+ uint64_t ol_flags = m->ol_flags;
+ uint64_t tunnel_type = ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK;
+
+ eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
+ parse_ethernet(eth_hdr, &info);
+ l3_hdr = (char *)eth_hdr + info.l2_len;
+ if (info.l4_proto == IPPROTO_UDP) {
+ struct rte_udp_hdr *udp_hdr;
+
+ udp_hdr = (struct rte_udp_hdr *)((char *)l3_hdr + info.l3_len);
+ if ((info.l2_len + info.l3_len + sizeof(struct rte_udp_hdr)) > m->data_len) {
+ PMD_LOG_ERR(TX, "UDP header exceeds mbuf data length");
+ ret = -1;
+ goto end;
+ }
+ parse_gtp(udp_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "gtp tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_GTP` flag");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GTP) {
+ PMD_LOG_ERR(TX, "gtp tunnel packet, tx offload has wrong "
+ "`%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_GTP` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+ parse_vxlan_gpe(udp_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "vxlan gpe tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE` flag");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE) {
+ PMD_LOG_ERR(TX, "vxlan gpe tunnel packet, tx offload has "
+ "wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+ parse_vxlan(udp_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "vxlan tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_VXLAN` flag");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_VXLAN) {
+ PMD_LOG_ERR(TX, "vxlan tunnel packet, tx offload has "
+ "wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_VXLAN` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+ parse_geneve(udp_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "geneve tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_GENEVE` flag");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GENEVE) {
+ PMD_LOG_ERR(TX, "geneve tunnel packet, tx offload has "
+ "wrong `%s` flag correct is `RTE_MBUF_F_TX_TUNNEL_GENEVE` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+
+ if (unlikely(RTE_ETH_IS_TUNNEL_PKT(m->packet_type) != 0)) {
+ PMD_LOG_ERR(TX, "Unknown tunnel packet UDP dst port:%u",
+ udp_hdr->dst_port);
+ ret = -1;
+ goto end;
+ }
+ } else if (info.l4_proto == TX_IPPROTO_GRE) {
+ struct simple_gre_hdr *gre_hdr;
+
+ gre_hdr = (struct simple_gre_hdr *)((char *)l3_hdr + info.l3_len);
+ parse_gre(gre_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "gre tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_GRE` flag.");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_GRE) {
+ PMD_LOG_ERR(TX, "gre tunnel packet, tx offload has "
+ "wrong `%s` flag, correct is `RTE_MBUF_F_TX_TUNNEL_GRE` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+ } else if (info.l4_proto == TX_IPPROTO_IPIP) {
+ void *encap_ip_hdr;
+
+ encap_ip_hdr = (char *)l3_hdr + info.l3_len;
+ parse_encap_ip(encap_ip_hdr, &info);
+ if (info.is_tunnel) {
+ if (!tunnel_type) {
+ PMD_LOG_ERR(TX, "Ipip tunnel packet missing tx "
+ "offload missing `RTE_MBUF_F_TX_TUNNEL_IPIP` flag");
+ ret = -1;
+ goto end;
+ }
+ if (tunnel_type != RTE_MBUF_F_TX_TUNNEL_IPIP) {
+ PMD_LOG_ERR(TX, "Ipip tunnel packet, tx offload has "
+ "wrong `%s` flag, correct is `RTE_MBUF_F_TX_TUNNEL_IPIP` flag",
+ rte_get_tx_ol_flag_name(tunnel_type));
+ ret = -1;
+ goto end;
+ }
+ goto check_len;
+ }
+ }
+
+check_len:
+ if (check_mbuf_len(&info, m) != 0) {
+ ret = -1;
+ goto end;
+ }
+ ret = check_ether_type(&info, m);
+
+end:
+ return ret;
+}
diff --git a/drivers/net/sxe2/sxe2_txrx_check_mbuf.h b/drivers/net/sxe2/sxe2_txrx_check_mbuf.h
new file mode 100644
index 0000000000..98197f85d9
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_txrx_check_mbuf.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd.
+ */
+
+#ifndef __SXE2_TXRX_CHECK_MBUF_H__
+#define __SXE2_TXRX_CHECK_MBUF_H__
+
+#include <rte_common.h>
+#include <rte_net.h>
+#include <rte_vect.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <ethdev_driver.h>
+
+struct offload_info {
+ uint16_t ethertype;
+ uint8_t gso_enable;
+ uint16_t l2_len;
+ uint16_t l3_len;
+ uint16_t l4_len;
+ uint8_t l4_proto;
+ uint8_t is_tunnel;
+ uint16_t outer_ethertype;
+ uint16_t outer_l2_len;
+ uint16_t outer_l3_len;
+ uint8_t outer_l4_proto;
+ uint16_t tso_segsz;
+ uint16_t tunnel_tso_segsz;
+ uint32_t pkt_len;
+};
+
+struct simple_gre_hdr {
+ uint16_t flags;
+ uint16_t proto;
+};
+
+__rte_unused int32_t sxe2_txrx_check_mbuf(struct rte_mbuf *m);
+#endif /* __SXE2_TXRX_CHECK_MBUF_H__ */
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox