* [PATCH v9 09/21] net/txgbe: fix link flow control config for Sapphire
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
SP chips have a hardware bug preventing XON flow control support,
so the driver disables it.
Fixes: 69ce8c8a4ce3 ("net/txgbe: support flow control")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_hw.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0d3310e15c..db45c5c0ef 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -1037,8 +1037,10 @@ s32 txgbe_fc_enable(struct txgbe_hw *hw)
for (i = 0; i < TXGBE_DCB_TC_MAX; i++) {
if ((hw->fc.current_mode & txgbe_fc_tx_pause) &&
hw->fc.high_water[i]) {
- fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]) |
- TXGBE_FCWTRLO_XON;
+ fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]);
+ /* Only AML support XON */
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40)
+ fcrtl |= TXGBE_FCWTRLO_XON;
fcrth = TXGBE_FCWTRHI_TH(hw->fc.high_water[i]) |
TXGBE_FCWTRHI_XOFF;
} else {
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 07/21] net/txgbe: fix Tx desc free logic
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
On some server environments, this driver caused TDM non-fatal errors
or PCIe request errors during Tx operation
In Amber-Lite NIC's Tx head write-back mode, the hardware periodically
writes back a head index pointing to the next descriptor it is adout
to process in Tx ring. All descriptors before the head are considered
processed by hardware and can be safely freed by the driver.
The root cause is that the driver can safely free a batch of descriptors
only when the hardware's write-back head pointer has advanced beyond all
descriptors in that batch, meaning they have all been processed by the
hardware. If the driver frees a descriptor before the hardware has
finished processing it, invalid memory access may occur, leading to the
observed bug.
To fix the issue, correct the boundary check in all three Tx cleanup
functions, each of which was missing the proper condition to prevent
freeing unprocessed descriptors.
Fixes: 8ada71d0bb7f ("net/txgbe: add Tx head write-back mode for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 16 +++++------
drivers/net/txgbe/txgbe_rxtx.h | 35 +++++++++++++++++++++++
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 10 +++----
3 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..d6efb3b8cc 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -98,12 +98,11 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
if (tx_last_dd >= txq->nb_tx_desc)
tx_last_dd -= txq->nb_tx_desc;
- volatile uint16_t head = (uint16_t)*txq->headwb_mem;
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
- if (txq->tx_next_dd > head && head > tx_last_dd)
- return 0;
- else if (tx_last_dd > txq->tx_next_dd &&
- (head > tx_last_dd || head < txq->tx_next_dd))
+ if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
return 0;
} else {
/* check DD bit on threshold descriptor */
@@ -645,12 +644,13 @@ txgbe_xmit_cleanup(struct txgbe_tx_queue *txq)
status = txr[desc_to_clean_to].dw3;
if (txq->headwb_mem) {
- u32 head = *txq->headwb_mem;
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
PMD_TX_FREE_LOG(DEBUG, "queue[%02d]: headwb_mem = %03d, desc_to_clean_to = %03d",
txq->reg_idx, head, desc_to_clean_to);
- /* we have caught up to head, no work left to do */
- if (desc_to_clean_to == head)
+ if (!txgbe_tx_headwb_desc_done(head, last_desc_cleaned, desc_to_clean_to))
return -(1);
} else {
if (!(status & rte_cpu_to_le_32(TXGBE_TXD_DD))) {
diff --git a/drivers/net/txgbe/txgbe_rxtx.h b/drivers/net/txgbe/txgbe_rxtx.h
index 02e2617cce..43c818cfbf 100644
--- a/drivers/net/txgbe/txgbe_rxtx.h
+++ b/drivers/net/txgbe/txgbe_rxtx.h
@@ -426,6 +426,41 @@ struct txgbe_txq_ops {
void (*reset)(struct txgbe_tx_queue *txq);
};
+/**
+ * Check whether Tx descriptors in the range (last, next] are done
+ * in Tx head write-back mode.
+ *
+ * In head write-back mode, the hardware periodically updates *headwb_mem
+ * with the index of the next descriptor it will process.
+ * All descriptors before the head are considered processed by hardware and can
+ * be safely freed. The descriptor pointed to by head itself is not yet processed.
+ *
+ * @param head
+ * Current hardware head index read from headwb_mem.
+ * @param last
+ * The highest-index descriptor cleaned in the previous round
+ * (exclusive: descriptors at or before this index are already freed).
+ * @param next
+ * The highest-index descriptor to be cleaned in this round
+ * (inclusive: this descriptor is the target of the current cleanup).
+ * @return
+ * true if all descriptors in the range (last, next] have been completed
+ * by hardware and can be freed, false otherwise.
+ */
+static inline bool
+txgbe_tx_headwb_desc_done(uint16_t head, uint16_t last, uint16_t next)
+{
+ if (next == head)
+ return false;
+ else if (next > head && head > last)
+ return false;
+ /* wrap case */
+ else if (last > next && (head > last || head < next))
+ return false;
+
+ return true;
+}
+
/* Takes an ethdev and a queue and sets up the tx function to be used based on
* the queue parameters. Used in tx_queue_setup by primary process and then
* in dev_init by secondary process when attaching to an existing ethdev.
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_common.h b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
index 00847d087b..77d7ff785b 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_common.h
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
@@ -94,11 +94,11 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
txq->tx_next_dd - txq->tx_free_thresh;
if (tx_last_dd >= txq->nb_tx_desc)
tx_last_dd -= txq->nb_tx_desc;
- volatile uint16_t head = (uint16_t)*txq->headwb_mem;
- if (txq->tx_next_dd > head && head > tx_last_dd)
- return 0;
- else if (tx_last_dd > txq->tx_next_dd &&
- (head > tx_last_dd || head < txq->tx_next_dd))
+ uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+ rte_memory_order_acquire);
+ const uint16_t head = (uint16_t)h;
+
+ if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
return 0;
} else {
/* check DD bit on threshold descriptor */
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 08/21] net/txgbe: fix link flow control registers for Amber-Lite
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
The flow control counter registers on AML NICs differ from those on SP
NICs. Update the register offsets accordingly to ensure the counters
work correctly.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_hw.c | 7 ++++++
drivers/net/txgbe/base/txgbe_regs.h | 2 ++
drivers/net/txgbe/base/txgbe_type.h | 4 ++++
drivers/net/txgbe/txgbe_ethdev.c | 34 +++++++++++++++++++----------
4 files changed, 36 insertions(+), 11 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c
index 0f3db3a1ad..0d3310e15c 100644
--- a/drivers/net/txgbe/base/txgbe_hw.c
+++ b/drivers/net/txgbe/base/txgbe_hw.c
@@ -394,6 +394,13 @@ s32 txgbe_clear_hw_cntrs(struct txgbe_hw *hw)
rd32(hw, TXGBE_PBTXLNKXON);
rd32(hw, TXGBE_PBTXLNKXOFF);
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
+ wr32(hw, TXGBE_PBRXLNKXON_AML, 0);
+ wr32(hw, TXGBE_PBRXLNKXOFF_AML, 0);
+ hw->last_stats.rx_xon_packets = 0;
+ hw->last_stats.rx_xoff_packets = 0;
+ }
+
/* DMA Stats */
rd32(hw, TXGBE_DMARXPKT);
rd32(hw, TXGBE_DMATXPKT);
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 3d1bc88430..22c46e3d56 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1085,6 +1085,8 @@ enum txgbe_5tuple_protocol {
#define TXGBE_PBRXDROP 0x019068
#define TXGBE_PBRXLNKXOFF 0x011988
#define TXGBE_PBRXLNKXON 0x011E0C
+#define TXGBE_PBRXLNKXOFF_AML 0x011F80
+#define TXGBE_PBRXLNKXON_AML 0x011F84
#define TXGBE_PBRXUPXON(up) (0x011E30 + (up) * 4)
#define TXGBE_PBRXUPXOFF(up) (0x011E10 + (up) * 4)
diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h
index ede780321f..505f598fb7 100644
--- a/drivers/net/txgbe/base/txgbe_type.h
+++ b/drivers/net/txgbe/base/txgbe_type.h
@@ -876,6 +876,10 @@ struct txgbe_hw {
u64 tx_qp_bytes;
u64 rx_qp_mc_packets;
} qp_last[TXGBE_MAX_QP];
+ struct {
+ u64 rx_xon_packets;
+ u64 rx_xoff_packets;
+ } last_stats;
rte_spinlock_t phy_lock;
/*amlite: new SW-FW mbox */
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index c97a7f1a4e..94ac89c7f6 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -2264,16 +2264,18 @@ txgbe_dev_reset(struct rte_eth_dev *dev)
return ret;
}
+#define TXGBE_UPDATE_COUNTER_32BIT_GENERIC(reg, last, count, reset) \
+ do { \
+ uint32_t current = rd32(hw, reg); \
+ if ((current) < (last)) \
+ current += 0x100000000ULL; \
+ if (reset) \
+ (last) = current; \
+ (count) = (uint32_t)((current) - (last)); \
+ } while (0)
+
#define UPDATE_QP_COUNTER_32bit(reg, last_counter, counter) \
- { \
- uint32_t current_counter = rd32(hw, reg); \
- if (current_counter < last_counter) \
- current_counter += 0x100000000LL; \
- if (!hw->offset_loaded) \
- last_counter = current_counter; \
- counter = current_counter - last_counter; \
- counter &= 0xFFFFFFFFLL; \
- }
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(reg, last_counter, counter, !hw->offset_loaded)
#define UPDATE_QP_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \
{ \
@@ -2331,8 +2333,18 @@ txgbe_read_stats_registers(struct txgbe_hw *hw,
hw_stats->up[i].rx_up_dropped +=
rd32(hw, TXGBE_PBRXMISS(i));
}
- hw_stats->rx_xon_packets += rd32(hw, TXGBE_PBRXLNKXON);
- hw_stats->rx_xoff_packets += rd32(hw, TXGBE_PBRXLNKXOFF);
+
+ if (hw->mac.type == txgbe_mac_aml || hw->mac.type == txgbe_mac_aml40) {
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(TXGBE_PBRXLNKXON_AML,
+ hw->last_stats.rx_xon_packets,
+ hw_stats->rx_xon_packets, !hw->offset_loaded);
+ TXGBE_UPDATE_COUNTER_32BIT_GENERIC(TXGBE_PBRXLNKXOFF_AML,
+ hw->last_stats.rx_xoff_packets,
+ hw_stats->rx_xoff_packets, !hw->offset_loaded);
+ } else {
+ hw_stats->rx_xon_packets += rd32(hw, TXGBE_PBRXLNKXON);
+ hw_stats->rx_xoff_packets += rd32(hw, TXGBE_PBRXLNKXOFF);
+ }
hw_stats->tx_xon_packets += rd32(hw, TXGBE_PBTXLNKXON);
hw_stats->tx_xoff_packets += rd32(hw, TXGBE_PBTXLNKXOFF);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 06/21] net/txgbe: fix link status check condition
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
The original code incorrectly used 'if (link_up)' instead of
'if (*link_up)', causing the condition to always evaluate to true
because the pointer itself is non-NULL. This led to incorrect speed
assignment.
Fixes: fb6eb170dfa2 ("net/txgbe: add basic link configuration for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_aml.c | 2 +-
drivers/net/txgbe/base/txgbe_aml40.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/txgbe/base/txgbe_aml.c b/drivers/net/txgbe/base/txgbe_aml.c
index b376eca5b5..de9a1b1c93 100644
--- a/drivers/net/txgbe/base/txgbe_aml.c
+++ b/drivers/net/txgbe/base/txgbe_aml.c
@@ -67,7 +67,7 @@ s32 txgbe_check_mac_link_aml(struct txgbe_hw *hw, u32 *speed,
*link_up = false;
}
- if (link_up) {
+ if (*link_up) {
switch (links_reg & TXGBE_CFG_PORT_ST_AML_LINK_MASK) {
case TXGBE_CFG_PORT_ST_AML_LINK_25G:
*speed = TXGBE_LINK_SPEED_25GB_FULL;
diff --git a/drivers/net/txgbe/base/txgbe_aml40.c b/drivers/net/txgbe/base/txgbe_aml40.c
index 733bbac13a..eefd7119fd 100644
--- a/drivers/net/txgbe/base/txgbe_aml40.c
+++ b/drivers/net/txgbe/base/txgbe_aml40.c
@@ -68,7 +68,7 @@ s32 txgbe_check_mac_link_aml40(struct txgbe_hw *hw, u32 *speed,
*link_up = false;
}
- if (link_up) {
+ if (*link_up) {
if ((links_reg & TXGBE_CFG_PORT_ST_AML_LINK_40G) ==
TXGBE_CFG_PORT_ST_AML_LINK_40G)
*speed = TXGBE_LINK_SPEED_40GB_FULL;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 05/21] net/txgbe: fix inaccuracy in Tx rate limiting
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
Amber-lite NIC's TX rate limiting has large deviations for small
packets. To address this, the following changes are made:
1. Set TDM_RL_ADJ (0x1820c) to 21B (includes 7B Ethernet preamble,
1B SFD, 1B EFD, and 12B IPG).
2) Remove the rate offset in the driver (e.g., 105 / 100, a rough
compensation value from Linux kernel driver tests).
After these changes, accuracy deviation for 64B packets is within
~5%, while large packets show lower deviation.
Fixes: a309ab43acf3 ("net/txgbe: support Tx queue rate limiting for Amber-Lite")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/base/txgbe_regs.h | 3 +++
drivers/net/txgbe/txgbe_ethdev.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h
index 95c585a025..3d1bc88430 100644
--- a/drivers/net/txgbe/base/txgbe_regs.h
+++ b/drivers/net/txgbe/base/txgbe_regs.h
@@ -1670,6 +1670,9 @@ enum txgbe_5tuple_protocol {
#define TXGBE_TDM_FACTOR_INT_SHIFT 16
#define TXGBE_TDM_FACTOR_FRA_SHIFT 2
+#define TXGBE_TDM_RL_ADJ 0x1820C
+ /* Ethernet framing overhead: 7B Ethernet preamble + 1B SFD + 1B EFD + 12B IPG */
+#define TXGBE_FRAME_OVERHEAD 21
#define TXGBE_TDM_RL_VM_IDX 0x018218
#define TXGBE_TDM_RL_VM_CFG 0x01821C
#define TXGBE_TDM_RL_CFG 0x018400
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 77870f3aee..c97a7f1a4e 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -4314,7 +4314,6 @@ txgbe_set_queue_rate_limit(struct rte_eth_dev *dev,
u16 frac;
link_speed = dev->data->dev_link.link_speed;
- tx_rate = tx_rate * 105 / 100;
/* Calculate the rate factor values to set */
factor_int = link_speed / tx_rate;
frac = (link_speed % tx_rate) * 10000 / tx_rate;
@@ -4324,6 +4323,7 @@ txgbe_set_queue_rate_limit(struct rte_eth_dev *dev,
factor_fra = 0;
}
+ wr32(hw, TXGBE_TDM_RL_ADJ, TXGBE_FRAME_OVERHEAD);
wr32(hw, TXGBE_TDM_RL_QUEUE_IDX, queue_idx);
wr32m(hw, TXGBE_TDM_RL_QUEUE_CFG,
TXGBE_TDM_FACTOR_INT_MASK, factor_int << TXGBE_TDM_FACTOR_INT_SHIFT);
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 04/21] net/ngbe: fix VF promiscuous and allmulticast
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
The configuration of allmulti and promiscuous modes conflicts
together. For instance, if we enable promiscuous mode, then enable and
disable allmulti, then the promiscuous mode is wrongly disabled.
To resolve this, the following changes are made:
- do nothing when we set/unset allmulti if promiscuous mode is on
- restore the proper mode (none or allmulti) when we disable
promiscuous mode
Fixes: 7744e90805b5 ("net/ngbe: add promiscuous and allmulticast ops for VF device")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_ethdev_vf.c b/drivers/net/ngbe/ngbe_ethdev_vf.c
index ea3a988df6..c440e02369 100644
--- a/drivers/net/ngbe/ngbe_ethdev_vf.c
+++ b/drivers/net/ngbe/ngbe_ethdev_vf.c
@@ -1196,9 +1196,13 @@ static int
ngbevf_dev_promiscuous_disable(struct rte_eth_dev *dev)
{
struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ int mode = NGBEVF_XCAST_MODE_NONE;
int ret;
- switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_NONE)) {
+ if (dev->data->all_multicast)
+ mode = NGBEVF_XCAST_MODE_ALLMULTI;
+
+ switch (hw->mac.update_xcast_mode(hw, mode)) {
case 0:
ret = 0;
break;
@@ -1219,7 +1223,7 @@ ngbevf_dev_allmulticast_enable(struct rte_eth_dev *dev)
struct ngbe_hw *hw = ngbe_dev_hw(dev);
int ret;
- if (dev->data->promiscuous == 1)
+ if (dev->data->promiscuous)
return 0;
switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_ALLMULTI)) {
@@ -1243,6 +1247,9 @@ ngbevf_dev_allmulticast_disable(struct rte_eth_dev *dev)
struct ngbe_hw *hw = ngbe_dev_hw(dev);
int ret;
+ if (dev->data->promiscuous)
+ return 0;
+
switch (hw->mac.update_xcast_mode(hw, NGBEVF_XCAST_MODE_MULTI)) {
case 0:
ret = 0;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 03/21] net/ngbe: add missing CDR config for YT PHY
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
According to the PHY vendor, when YT8531S operates in UTP-to-Fiber or
RGMII-to-Fiber mode with auto-negotiation disabled (Force mode),
additional CDR (Clock Data Recovery) configuration is required to
improve link connectivity. Without this config, link may be unstable
or fail to establish.
Fixes: f1268369403d ("net/ngbe: support autoneg on/off for external PHY SFI mode")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.c b/drivers/net/ngbe/base/ngbe_phy_yt.c
index d110fbc8b2..ab0778d246 100644
--- a/drivers/net/ngbe/base/ngbe_phy_yt.c
+++ b/drivers/net/ngbe/base/ngbe_phy_yt.c
@@ -264,6 +264,9 @@ s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
value = YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN |
YT_BCR_DUPLEX | YT_BCR_SPEED_SELECT1;
} else {
+ /* force mode need to config cdr */
+ ngbe_write_phy_reg_sds_ext_yt(hw, 0x3, 0, 0x1434);
+ ngbe_write_phy_reg_sds_ext_yt(hw, 0xe, 0, 0x163);
value = YT_BCR_RESET | YT_BCR_DUPLEX;
if (speed & NGBE_LINK_SPEED_1GB_FULL)
value |= YT_BCR_SPEED_SELECT1;
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 01/21] net/txgbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
Remove four redundant counters (tx_xon_packets, rx_xon_packets,
tx_xoff_packets and rx_xoff_packets) from xstats, as they were duplicates
of tx_flow_control_xon_packets and others. Both sets were reading the same
registers but being output twice under different names. After removing
these entries, the flow control counters in DPDK now align with those in
our Linux kernel driver.
Fixes: 91fe49c87d76 ("net/txgbe: support device xstats")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/txgbe/txgbe_ethdev.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c
index 0f484dfe91..77870f3aee 100644
--- a/drivers/net/txgbe/txgbe_ethdev.c
+++ b/drivers/net/txgbe/txgbe_ethdev.c
@@ -261,11 +261,6 @@ static const struct rte_txgbe_xstats_name_off rte_txgbe_stats_strings[] = {
HW_XSTAT(tx_size_1024_to_max_packets),
/* Flow Control */
- HW_XSTAT(tx_xon_packets),
- HW_XSTAT(rx_xon_packets),
- HW_XSTAT(tx_xoff_packets),
- HW_XSTAT(rx_xoff_packets),
-
HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"),
HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"),
HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"),
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 02/21] net/ngbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260622111111.21024-1-zaiyuwang@trustnetic.com>
Remove four redundant counters (tx_xon_packets, rx_xon_packets,
tx_xoff_packets and rx_xoff_packets) from xstats, as they were duplicates
of tx_flow_control_xon_packets and others. Both sets were reading the same
registers but being output twice under different names. After removing
these entries, the flow control counters in DPDK now align with those in
our Linux kernel driver.
Fixes: 8b433d04adc9 ("net/ngbe: support device xstats")
Cc: stable@dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang@trustnetic.com>
---
drivers/net/ngbe/ngbe_ethdev.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c
index f7b4a8b159..09bcd791ed 100644
--- a/drivers/net/ngbe/ngbe_ethdev.c
+++ b/drivers/net/ngbe/ngbe_ethdev.c
@@ -227,11 +227,6 @@ static const struct rte_ngbe_xstats_name_off rte_ngbe_stats_strings[] = {
HW_XSTAT(tx_size_1024_to_max_packets),
/* Flow Control */
- HW_XSTAT(tx_xon_packets),
- HW_XSTAT(rx_xon_packets),
- HW_XSTAT(tx_xoff_packets),
- HW_XSTAT(rx_xoff_packets),
-
HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"),
HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"),
HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"),
--
2.21.0.windows.1
^ permalink raw reply related
* [PATCH v9 00/21] Wangxun Fixes
From: Zaiyu Wang @ 2026-06-22 11:10 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang
In-Reply-To: <20260423034024.14404-1-zaiyuwang@trustnetic.com>
This series fixes several issues found on Wangxun Emerald, Sapphire and
Amber-lite NICs, with a focus on link-related problems.
---
v9:
- Fixed several checkpatch errors
---
v8:
- Fixed compilation error by replacing RTE_ETH_DEV_TO_PCI with RTE_CLASS_TO_BUS_DEVICE
---
v7:
- Fixed inverted semantics of is_flat_mem to match SFF8636
---
v6:
- Fixed more issues identified by AI review
---
v5:
- Fixed issues identified by AI review
---
v4:
- Fixed issues identified by devtools scripts
---
v3:
- Addressed Stephen's comments
---
v2:
- Fixed compilation error and code style issues
---
Zaiyu Wang (21):
net/txgbe: remove duplicate xstats counters
net/ngbe: remove duplicate xstats counters
net/ngbe: add missing CDR config for YT PHY
net/ngbe: fix VF promiscuous and allmulticast
net/txgbe: fix inaccuracy in Tx rate limiting
net/txgbe: fix link status check condition
net/txgbe: fix Tx desc free logic
net/txgbe: fix link flow control registers for Amber-Lite
net/txgbe: fix link flow control config for Sapphire
net/txgbe: fix a mass of unknown interrupts
net/txgbe: fix traffic class priority configuration
net/txgbe: fix link stability for 25G NIC
net/txgbe: fix link stability for 40G NIC
net/txgbe: fix link stability for Amber-Lite backplane mode
net/txgbe: fix FEC mode configuration on 25G NIC
net/txgbe: fix SFP module identification
net/txgbe: fix get module info operation
net/txgbe: fix get EEPROM operation
net/txgbe: fix to reset Tx write-back pointer
net/txgbe: fix to enable Tx desc check
net/txgbe: fix temperature track for AML NIC
drivers/net/ngbe/base/ngbe_phy_yt.c | 3 +
drivers/net/ngbe/ngbe_ethdev.c | 5 -
drivers/net/ngbe/ngbe_ethdev_vf.c | 11 +-
drivers/net/txgbe/base/meson.build | 2 +
drivers/net/txgbe/base/txgbe.h | 2 +
drivers/net/txgbe/base/txgbe_aml.c | 185 +-
drivers/net/txgbe/base/txgbe_aml.h | 6 +-
drivers/net/txgbe/base/txgbe_aml40.c | 114 +-
drivers/net/txgbe/base/txgbe_aml40.h | 6 +-
drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 +-
drivers/net/txgbe/base/txgbe_e56.c | 3773 +++++++++++++++++++++
drivers/net/txgbe/base/txgbe_e56.h | 1753 ++++++++++
drivers/net/txgbe/base/txgbe_e56_bp.c | 2597 ++++++++++++++
drivers/net/txgbe/base/txgbe_e56_bp.h | 282 ++
drivers/net/txgbe/base/txgbe_hw.c | 54 +-
drivers/net/txgbe/base/txgbe_hw.h | 4 +-
drivers/net/txgbe/base/txgbe_osdep.h | 4 +
drivers/net/txgbe/base/txgbe_phy.c | 362 +-
drivers/net/txgbe/base/txgbe_phy.h | 46 +-
drivers/net/txgbe/base/txgbe_regs.h | 13 +-
drivers/net/txgbe/base/txgbe_type.h | 43 +-
drivers/net/txgbe/txgbe_ethdev.c | 472 ++-
drivers/net/txgbe/txgbe_ethdev.h | 7 +-
drivers/net/txgbe/txgbe_rxtx.c | 109 +-
drivers/net/txgbe/txgbe_rxtx.h | 36 +
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 17 +-
26 files changed, 9464 insertions(+), 444 deletions(-)
create mode 100644 drivers/net/txgbe/base/txgbe_e56.c
create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
--
2.21.0.windows.1
^ permalink raw reply
* RE: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
From: Zaiyu Wang @ 2026-06-22 11:09 UTC (permalink / raw)
To: 'Stephen Hemminger'; +Cc: dev
In-Reply-To: <20260617085355.0a87d7ee@phoenix.local>
> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Wednesday, June 17, 2026 11:54 PM
> To: Zaiyu Wang <zaiyuwang@trustnetic.com>; Zaiyu Wang <zaiyuwang@trustnetic.com>
> Cc: dev@dpdk.org; stable@dpdk.org; Jiawen Wu <jiawenwu@trustnetic.com>; dev@dpdk.org;
> stable@dpdk.org; Jiawen Wu <jiawenwu@trustnetic.com>
> Subject: Re: [PATCH v8 12/21] net/txgbe: fix link stability for 25G NIC
>
> On Wed, 17 Jun 2026 16:12:59 +0800
> Zaiyu Wang <zaiyuwang@trustnetic.com> wrote:
>
> > +void
> > +set_fields_e56(unsigned int *src_data, unsigned int bit_high,
> > + unsigned int bit_low, unsigned int set_value) {
>
> Function could be static here?
Hi Stephen,
Thanks for your time. This function is used in both txgbe_e56.c (for general PHY
configuration) and txgbe_e56_bp.c (for backplane mode configuration). Therefore, making it
static would not be feasible?
I have also fixed the other issues you pointed out, including the spelling corrections,
replacing tabs with spaces in log messages, and removing the term "master" from comments.
Best regards,
Zaiyu
^ permalink raw reply
* Re: [PATCH v2 09/10] bus/vmbus: store name in bus specific device
From: Bruce Richardson @ 2026-06-22 10:28 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Wei Hu
In-Reply-To: <20260618152826.490569-10-david.marchand@redhat.com>
On Thu, Jun 18, 2026 at 05:28:24PM +0200, David Marchand wrote:
> The device name is allocated with strdup() during scan and freed in
> several places. However, when this bus cleanup is converted to use the
> EAL generic helper, freeing the device object will require a custom
> helper to also free the device name (and for this, a cast will be
> needed).
>
> Instead, add an embedded name array to rte_vmbus_device structure
> (char name[RTE_DEV_NAME_MAX_LEN]) which is sufficient for all VMBUS
> device names (UUID format: 36 characters, or shorter legacy format).
>
> This simplifies the device freeing to a simple free() call.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
Seems reasonable to me.
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply
* Re: [PATCH v2 08/10] bus: implement cleanup in EAL
From: Bruce Richardson @ 2026-06-22 10:26 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Sachin Saxena, Rosen Xu, Chenbo Xia,
Nipun Gupta, Tomasz Duszynski, Wei Hu
In-Reply-To: <20260618152826.490569-9-david.marchand@redhat.com>
On Thu, Jun 18, 2026 at 05:28:23PM +0200, David Marchand wrote:
> Introduce a generic cleanup helper rte_bus_generic_cleanup() that
> eliminates code duplication across bus cleanup implementations:
> unplug probed devices, remove devargs, remove from bus list,
> and free device structures.
>
> Add .free_device operation to struct rte_bus to allow buses to specify
> how to free their device structures.
> Update all buses for the new .cleanup and RTE_REGISTER_BUS prototypes.
>
> Convert to rte_bus_generic_cleanup() the buses that have both a .cleanup
> and .unplug_device: this requires implementing .free_device for them.
>
> Untouched buses are:
> - dma/idxd which has no unplug support,
> - bus/cdx which has unplug support, but no cleanup was implemented so
> far,
> - NXP buses:
> - bus/dpaa and bus/fslmc have many issues on interrupt
> allocation/setup/freeing or VFIO setup/release,
> - bus/fslmc cleanup callback is actually implemented in its internal
> VFIO layer and requires too much refactoring,
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply
* Re: [PATCH v2 07/10] bus: align unplug with device probe
From: Bruce Richardson @ 2026-06-22 10:19 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Parav Pandit, Xueming Li, Nipun Gupta, Nikhil Agarwal,
Sachin Saxena, Rosen Xu, Chenbo Xia, Tomasz Duszynski
In-Reply-To: <20260618152826.490569-8-david.marchand@redhat.com>
On Thu, Jun 18, 2026 at 05:28:22PM +0200, David Marchand wrote:
> Refactor bus unplug operations to be the counterpart of probe_device.
> The (renamed) unplug operation now only handles:
> - Driver removal (calling the driver's remove callback)
> - Freeing probe-allocated resources (interrupts, mappings)
>
> Device deletion (devargs removal, bus removal, freeing device
> structure) is now handled only during bus cleanup, not in unplug.
>
> Additionally, move driver pointer clearing from individual bus unplug
> operations to EAL's local_dev_remove() where the unplug operation is
> invoked. This centralizes driver lifecycle management and eliminates
> code duplication across bus drivers.
>
> For vdev, add a check in rte_vdev_uninit() since this public API can
> be called on devices without a driver attached.
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
Running an AI correctness review reports a potential issue with ifpga bus
after this patch. Maybe worth a double check.
/Bruce
In ifpga_alloc_afu_dev (called at scan time, before any probe),
afu_dev->intr_handle is allocated unconditionally.
In the old ifpga_cleanup, the "goto free:" label ran for all devices, so
intr_handle was freed unconditionally. In the new ifpga_cleanup,
intr_handle is only freed via ifpga_unplug_device, which is only called
when rte_dev_is_probed() returns true. For any ifpga device discovered
during scan but never successfully probed (no matching driver, failed
probe, blocked devargs), intr_handle is leaked. The fix should free it
unconditionally in ifpga_cleanup, outside the rte_dev_is_probed block.
> ---
> doc/guides/prog_guide/device_hotplug.rst | 18 ++++---
> drivers/bus/auxiliary/auxiliary_common.c | 46 ++++++----------
> drivers/bus/cdx/cdx.c | 29 ++--------
> drivers/bus/fslmc/fslmc_bus.c | 7 +--
> drivers/bus/ifpga/ifpga_bus.c | 63 ++++++++++------------
> drivers/bus/pci/pci_common.c | 57 ++++----------------
> drivers/bus/platform/platform.c | 16 +++---
> drivers/bus/uacce/uacce.c | 67 ++++++++----------------
> drivers/bus/vdev/vdev.c | 53 ++++++++-----------
> lib/eal/common/eal_common_dev.c | 8 +--
> lib/eal/include/bus_driver.h | 4 +-
> 11 files changed, 129 insertions(+), 239 deletions(-)
>
> diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
> index 7eb7fbcc2b..d21ba0c244 100644
> --- a/doc/guides/prog_guide/device_hotplug.rst
> +++ b/doc/guides/prog_guide/device_hotplug.rst
> @@ -165,7 +165,7 @@ using ``rte_dev_event_callback_register()`` function.
> on the device in question.
> When ``RTE_DEV_EVENT_REMOVE`` event is delivered,
> it indicates that the kernel has removed the device;
> - the application should call ``rte_dev_remove()`` to clean up EAL resources.
> + the application should call ``rte_dev_remove()`` to unplug the device driver.
>
>
> Event Notification Usage
> @@ -256,13 +256,17 @@ When ``rte_dev_remove()`` is called, the following sequence occurs:
> See `Multi-process Synchronization`_ for details.
>
> #. **Device Unplug**:
> - The bus's ``unplug()`` method is called (``dev->bus->unplug()``),
> - which triggers the driver's remove function.
> - This typically stops device operations, releases device resources,
> - unmaps memory regions, and unregisters from subsystems.
> + The bus's ``unplug_device()`` method is called (``dev->bus->unplug_device()``),
> + which triggers the driver's remove function
> + and releases resources allocated during probe
> + (such as interrupt handles and device memory mappings).
>
> -#. **Devargs Cleanup**:
> - The devargs associated with the device are removed from the global list.
> +.. note::
> +
> + The device structure, its devargs, and its entry in the bus device list
> + are NOT freed during ``rte_dev_remove()``.
> + They remain in memory until ``rte_eal_cleanup()`` is called,
> + at which point the bus's ``cleanup()`` method handles complete device deletion.
>
>
> Multi-process Synchronization
> diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
> index 048aacf254..10f466e57a 100644
> --- a/drivers/bus/auxiliary/auxiliary_common.c
> +++ b/drivers/bus/auxiliary/auxiliary_common.c
> @@ -122,13 +122,11 @@ auxiliary_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return ret;
> }
>
> -/*
> - * Call the remove() function of the driver.
> - */
> static int
> -rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
> +auxiliary_unplug_device(struct rte_device *rte_dev)
> {
> - const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> + const struct rte_auxiliary_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
> + struct rte_auxiliary_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
> @@ -140,8 +138,8 @@ rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> + rte_intr_instance_free(dev->intr_handle);
> + dev->intr_handle = NULL;
>
> return 0;
> }
> @@ -181,22 +179,6 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
> rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
> }
>
> -static int
> -auxiliary_unplug(struct rte_device *dev)
> -{
> - struct rte_auxiliary_device *adev = RTE_BUS_DEVICE(dev, *adev);
> - int ret;
> -
> - ret = rte_auxiliary_driver_remove_dev(adev);
> - if (ret == 0) {
> - rte_bus_remove_device(&auxiliary_bus, &adev->device);
> - rte_devargs_remove(dev->devargs);
> - rte_intr_instance_free(adev->intr_handle);
> - free(adev);
> - }
> - return ret;
> -}
> -
> static int
> auxiliary_cleanup(void)
> {
> @@ -206,13 +188,17 @@ auxiliary_cleanup(void)
> RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
> int ret;
>
> - if (!rte_dev_is_probed(&dev->device))
> - continue;
> - ret = auxiliary_unplug(&dev->device);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = auxiliary_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
> +
> + rte_devargs_remove(dev->device.devargs);
> + rte_bus_remove_device(&auxiliary_bus, &dev->device);
> + free(dev);
> }
>
> return error;
> @@ -265,7 +251,7 @@ struct rte_bus auxiliary_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = auxiliary_bus_match,
> .probe_device = auxiliary_probe_device,
> - .unplug = auxiliary_unplug,
> + .unplug_device = auxiliary_unplug_device,
> .parse = auxiliary_parse,
> .dma_map = auxiliary_dma_map,
> .dma_unmap = auxiliary_dma_unmap,
> diff --git a/drivers/bus/cdx/cdx.c b/drivers/bus/cdx/cdx.c
> index 2443161e1a..c0b46a41ad 100644
> --- a/drivers/bus/cdx/cdx.c
> +++ b/drivers/bus/cdx/cdx.c
> @@ -374,14 +374,11 @@ rte_cdx_unregister(struct rte_cdx_driver *driver)
> rte_bus_remove_driver(&rte_cdx_bus, &driver->driver);
> }
>
> -/*
> - * If vendor/device ID match, call the remove() function of the
> - * driver.
> - */
> static int
> -cdx_detach_dev(struct rte_cdx_device *dev)
> +cdx_unplug_device(struct rte_device *rte_dev)
> {
> - const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> + const struct rte_cdx_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
> + struct rte_cdx_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> CDX_BUS_DEBUG("detach device %s using driver: %s",
> @@ -393,9 +390,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> -
> rte_cdx_unmap_device(dev);
>
> rte_intr_instance_free(dev->intr_handle);
> @@ -404,21 +398,6 @@ cdx_detach_dev(struct rte_cdx_device *dev)
> return 0;
> }
>
> -static int
> -cdx_unplug(struct rte_device *dev)
> -{
> - struct rte_cdx_device *cdx_dev = RTE_BUS_DEVICE(dev, *cdx_dev);
> - int ret;
> -
> - ret = cdx_detach_dev(cdx_dev);
> - if (ret == 0) {
> - rte_bus_remove_device(&rte_cdx_bus, &cdx_dev->device);
> - rte_devargs_remove(dev->devargs);
> - free(cdx_dev);
> - }
> - return ret;
> -}
> -
> static int
> cdx_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
> {
> @@ -452,7 +431,7 @@ static struct rte_bus rte_cdx_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = cdx_bus_match,
> .probe_device = cdx_probe_device,
> - .unplug = cdx_unplug,
> + .unplug_device = cdx_unplug_device,
> .parse = cdx_parse,
> .dma_map = cdx_dma_map,
> .dma_unmap = cdx_dma_unmap,
> diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
> index c7549a361a..dca4c5b182 100644
> --- a/drivers/bus/fslmc/fslmc_bus.c
> +++ b/drivers/bus/fslmc/fslmc_bus.c
> @@ -520,6 +520,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
> return 0;
> }
>
> + /* FIXME: probe_device should allocate intr_handle */
> ret = drv->probe(drv, dev);
> if (ret != 0) {
> DPAA2_BUS_ERR("Unable to probe");
> @@ -531,7 +532,7 @@ fslmc_bus_probe_device(struct rte_driver *driver, struct rte_device *rte_dev)
> }
>
> static int
> -fslmc_bus_unplug(struct rte_device *rte_dev)
> +fslmc_bus_unplug_device(struct rte_device *rte_dev)
> {
> struct rte_dpaa2_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> const struct rte_dpaa2_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
> @@ -540,7 +541,7 @@ fslmc_bus_unplug(struct rte_device *rte_dev)
> int ret = drv->remove(dev);
> if (ret != 0)
> return ret;
> - dev->device.driver = NULL;
> + /* FIXME: unplug_device should free intr_handle */
> DPAA2_BUS_INFO("%s Un-Plugged", dev->device.name);
> return 0;
> }
> @@ -558,7 +559,7 @@ struct rte_bus rte_fslmc_bus = {
> .get_iommu_class = rte_dpaa2_get_iommu_class,
> .match = fslmc_bus_match,
> .probe_device = fslmc_bus_probe_device,
> - .unplug = fslmc_bus_unplug,
> + .unplug_device = fslmc_bus_unplug_device,
> .dev_iterate = rte_bus_generic_dev_iterate,
> };
>
> diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
> index 2c22329f65..394b777916 100644
> --- a/drivers/bus/ifpga/ifpga_bus.c
> +++ b/drivers/bus/ifpga/ifpga_bus.c
> @@ -276,6 +276,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return afu_drv->probe(afu_dev);
> }
>
> +static int
> +ifpga_unplug_device(struct rte_device *dev)
> +{
> + const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
> + struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
> + int ret = 0;
> +
> + if (afu_drv->remove) {
> + ret = afu_drv->remove(afu_dev);
> + if (ret)
> + return ret;
> + }
> +
> + rte_intr_instance_free(afu_dev->intr_handle);
> + afu_dev->intr_handle = NULL;
> +
> + return 0;
> +}
> +
> /*
> * Cleanup the content of the Intel FPGA bus, and call the remove() function
> * for all registered devices.
> @@ -287,52 +306,24 @@ ifpga_cleanup(void)
> int error = 0;
>
> RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
> - const struct rte_afu_driver *drv;
> int ret = 0;
>
> - if (!rte_dev_is_probed(&afu_dev->device))
> - goto free;
> - drv = RTE_BUS_DRIVER(afu_dev->device.driver, *drv);
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(afu_dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&afu_dev->device)) {
> + ret = ifpga_unplug_device(&afu_dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
> - afu_dev->device.driver = NULL;
>
> -free:
> - rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> rte_devargs_remove(afu_dev->device.devargs);
> - rte_intr_instance_free(afu_dev->intr_handle);
> + rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> free(afu_dev);
> }
>
> return error;
> }
>
> -static int
> -ifpga_unplug(struct rte_device *dev)
> -{
> - struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
> - const struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(dev->driver, *afu_drv);
> - int ret;
> -
> - ret = afu_drv->remove(afu_dev);
> - if (ret)
> - return ret;
> -
> - rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
> -
> - rte_devargs_remove(dev->devargs);
> - rte_intr_instance_free(afu_dev->intr_handle);
> - free(afu_dev);
> - return 0;
> -
> -}
> -
> static int
> ifpga_parse(const char *name, void *addr)
> {
> @@ -384,7 +375,7 @@ static struct rte_bus rte_ifpga_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = ifpga_bus_match,
> .probe_device = ifpga_probe_device,
> - .unplug = ifpga_unplug,
> + .unplug_device = ifpga_unplug_device,
> .parse = ifpga_parse,
> };
>
> diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
> index 791e9a7b49..bf4822f7ec 100644
> --- a/drivers/bus/pci/pci_common.c
> +++ b/drivers/bus/pci/pci_common.c
> @@ -282,13 +282,10 @@ pci_probe_device(struct rte_driver *drv, struct rte_device *dev)
> return ret;
> }
>
> -/*
> - * If vendor/device ID match, call the remove() function of the
> - * driver.
> - */
> static int
> -rte_pci_detach_dev(struct rte_pci_device *dev)
> +pci_unplug_device(struct rte_device *rte_dev)
> {
> + struct rte_pci_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> struct rte_pci_addr *loc;
> const struct rte_pci_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> int ret = 0;
> @@ -308,9 +305,6 @@ rte_pci_detach_dev(struct rte_pci_device *dev)
> return ret;
> }
>
> - /* clear driver structure */
> - dev->device.driver = NULL;
> -
> if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
> /* unmap resources for devices that use igb_uio */
> rte_pci_unmap_device(dev);
> @@ -330,33 +324,17 @@ pci_cleanup(void)
> int error = 0;
>
> RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
> - const struct rte_pci_driver *drv;
> int ret = 0;
>
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> - drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = pci_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> }
>
> - if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
> - rte_pci_unmap_device(dev);
> -
> - dev->device.driver = NULL;
> -
> -free:
> - /* free interrupt handles */
> - rte_intr_instance_free(dev->intr_handle);
> - dev->intr_handle = NULL;
> - rte_intr_instance_free(dev->vfio_req_intr_handle);
> - dev->vfio_req_intr_handle = NULL;
> -
> + rte_devargs_remove(dev->device.devargs);
> rte_bus_remove_device(&rte_pci_bus, &dev->device);
> pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
> }
> @@ -521,21 +499,6 @@ pci_sigbus_handler(const void *failure_addr)
> return ret;
> }
>
> -static int
> -pci_unplug(struct rte_device *dev)
> -{
> - struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
> - int ret;
> -
> - ret = rte_pci_detach_dev(pdev);
> - if (ret == 0) {
> - rte_bus_remove_device(&rte_pci_bus, &pdev->device);
> - rte_devargs_remove(dev->devargs);
> - pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
> - }
> - return ret;
> -}
> -
> static int
> pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
> {
> @@ -784,7 +747,7 @@ struct rte_bus rte_pci_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = pci_bus_match,
> .probe_device = pci_probe_device,
> - .unplug = pci_unplug,
> + .unplug_device = pci_unplug_device,
> .parse = pci_parse,
> .dev_compare = pci_dev_compare,
> .devargs_parse = rte_pci_devargs_parse,
> diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
> index 170a2e03d0..5b3c78a505 100644
> --- a/drivers/bus/platform/platform.c
> +++ b/drivers/bus/platform/platform.c
> @@ -416,19 +416,15 @@ device_release_driver(struct rte_platform_device *pdev)
> if (ret)
> PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
> }
> -
> - pdev->device.driver = NULL;
> }
>
> static int
> -platform_bus_unplug(struct rte_device *dev)
> +platform_bus_unplug_device(struct rte_device *dev)
> {
> struct rte_platform_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
>
> device_release_driver(pdev);
> device_cleanup(pdev);
> - rte_devargs_remove(pdev->device.devargs);
> - free(pdev);
>
> return 0;
> }
> @@ -501,10 +497,12 @@ platform_bus_cleanup(void)
> struct rte_platform_device *pdev;
>
> RTE_BUS_FOREACH_DEV(pdev, &platform_bus) {
> + if (rte_dev_is_probed(&pdev->device))
> + platform_bus_unplug_device(&pdev->device);
> +
> + rte_devargs_remove(pdev->device.devargs);
> rte_bus_remove_device(&platform_bus, &pdev->device);
> - if (!rte_dev_is_probed(&pdev->device))
> - continue;
> - platform_bus_unplug(&pdev->device);
> + free(pdev);
> }
>
> return 0;
> @@ -516,7 +514,7 @@ static struct rte_bus platform_bus = {
> .find_device = rte_bus_generic_find_device,
> .match = platform_bus_match,
> .probe_device = platform_bus_probe_device,
> - .unplug = platform_bus_unplug,
> + .unplug_device = platform_bus_unplug_device,
> .parse = platform_bus_parse,
> .dma_map = platform_bus_dma_map,
> .dma_unmap = platform_bus_dma_unmap,
> diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
> index 8a3c55b248..bfe1f26557 100644
> --- a/drivers/bus/uacce/uacce.c
> +++ b/drivers/bus/uacce/uacce.c
> @@ -385,40 +385,10 @@ uacce_probe_device(struct rte_driver *drv, struct rte_device *dev)
> }
>
> static int
> -uacce_cleanup(void)
> +uacce_unplug_device(struct rte_device *rte_dev)
> {
> - struct rte_uacce_device *dev;
> - int error = 0;
> -
> - RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
> - const struct rte_uacce_driver *dr;
> - int ret = 0;
> -
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> - dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> - if (dr->remove == NULL)
> - goto free;
> -
> - ret = dr->remove(dev);
> - if (ret < 0) {
> - rte_errno = errno;
> - error = -1;
> - }
> - dev->device.driver = NULL;
> -
> -free:
> - rte_bus_remove_device(&uacce_bus, &dev->device);
> - free(dev);
> - }
> -
> - return error;
> -}
> -
> -static int
> -uacce_detach_dev(struct rte_uacce_device *dev)
> -{
> - const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(dev->device.driver, *dr);
> + const struct rte_uacce_driver *dr = RTE_BUS_DRIVER(rte_dev->driver, *dr);
> + struct rte_uacce_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
> int ret = 0;
>
> UACCE_BUS_DEBUG("detach device %s using driver: %s", dev->device.name, dr->driver.name);
> @@ -429,25 +399,32 @@ uacce_detach_dev(struct rte_uacce_device *dev)
> return ret;
> }
>
> - dev->device.driver = NULL;
> -
> return 0;
> }
>
> static int
> -uacce_unplug(struct rte_device *dev)
> +uacce_cleanup(void)
> {
> - struct rte_uacce_device *uacce_dev = RTE_BUS_DEVICE(dev, *uacce_dev);
> - int ret;
> + struct rte_uacce_device *dev;
> + int error = 0;
>
> - ret = uacce_detach_dev(uacce_dev);
> - if (ret == 0) {
> - rte_bus_remove_device(&uacce_bus, &uacce_dev->device);
> - rte_devargs_remove(dev->devargs);
> - free(uacce_dev);
> + RTE_BUS_FOREACH_DEV(dev, &uacce_bus) {
> + int ret = 0;
> +
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = uacce_unplug_device(&dev->device);
> + if (ret < 0) {
> + rte_errno = errno;
> + error = -1;
> + }
> + }
> +
> + rte_devargs_remove(dev->device.devargs);
> + rte_bus_remove_device(&uacce_bus, &dev->device);
> + free(dev);
> }
>
> - return ret;
> + return error;
> }
>
> static int
> @@ -577,7 +554,7 @@ static struct rte_bus uacce_bus = {
> .cleanup = uacce_cleanup,
> .match = uacce_bus_match,
> .probe_device = uacce_probe_device,
> - .unplug = uacce_unplug,
> + .unplug_device = uacce_unplug_device,
> .find_device = rte_bus_generic_find_device,
> .parse = uacce_parse,
> .dev_iterate = rte_bus_generic_dev_iterate,
> diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
> index 09221ccdea..7e94f86e28 100644
> --- a/drivers/bus/vdev/vdev.c
> +++ b/drivers/bus/vdev/vdev.c
> @@ -343,19 +343,15 @@ rte_vdev_init(const char *name, const char *args)
> }
>
> static int
> -vdev_remove_driver(struct rte_vdev_device *dev)
> +vdev_unplug_device(struct rte_device *rte_dev)
> {
> - const char *name = rte_vdev_device_name(dev);
> - const struct rte_vdev_driver *driver;
> + const struct rte_vdev_driver *driver = RTE_BUS_DRIVER(rte_dev->driver, *driver);
> + struct rte_vdev_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
>
> - if (!dev->device.driver) {
> - VDEV_LOG(DEBUG, "no driver attach to device %s", name);
> - return 1;
> - }
> + if (driver->remove)
> + return driver->remove(dev);
>
> - driver = RTE_BUS_DRIVER(dev->device.driver, *driver);
> -
> - return driver->remove(dev);
> + return 0;
> }
>
> RTE_EXPORT_SYMBOL(rte_vdev_uninit)
> @@ -376,7 +372,12 @@ rte_vdev_uninit(const char *name)
> goto unlock;
> }
>
> - ret = vdev_remove_driver(dev);
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = vdev_unplug_device(&dev->device);
> + } else {
> + VDEV_LOG(DEBUG, "no driver attach to device %s", name);
> + ret = 1;
> + }
> if (ret)
> goto unlock;
>
> @@ -553,27 +554,21 @@ vdev_cleanup(void)
> struct rte_vdev_device *dev;
> int error = 0;
>
> + rte_spinlock_recursive_lock(&vdev_device_list_lock);
> RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
> - const struct rte_vdev_driver *drv;
> int ret;
>
> - if (!rte_dev_is_probed(&dev->device))
> - goto free;
> -
> - drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
> -
> - if (drv->remove == NULL)
> - goto free;
> -
> - ret = drv->remove(dev);
> - if (ret < 0)
> - error = -1;
> + if (rte_dev_is_probed(&dev->device)) {
> + ret = vdev_unplug_device(&dev->device);
> + if (ret < 0)
> + error = -1;
> + }
>
> - dev->device.driver = NULL;
> -free:
> + rte_devargs_remove(dev->device.devargs);
> rte_bus_remove_device(&rte_vdev_bus, &dev->device);
> free(dev);
> }
> + rte_spinlock_recursive_unlock(&vdev_device_list_lock);
>
> return error;
> }
> @@ -591,12 +586,6 @@ vdev_find_device(const struct rte_bus *bus, const struct rte_device *start,
> return dev;
> }
>
> -static int
> -vdev_unplug(struct rte_device *dev)
> -{
> - return rte_vdev_uninit(dev->name);
> -}
> -
> static enum rte_iova_mode
> vdev_get_iommu_class(void)
> {
> @@ -623,7 +612,7 @@ static struct rte_bus rte_vdev_bus = {
> .find_device = vdev_find_device,
> .match = vdev_bus_match,
> .probe_device = vdev_probe_device,
> - .unplug = vdev_unplug,
> + .unplug_device = vdev_unplug_device,
> .parse = vdev_parse,
> .dma_map = vdev_dma_map,
> .dma_unmap = vdev_dma_unmap,
> diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
> index 2a2103ec57..762ed09e21 100644
> --- a/lib/eal/common/eal_common_dev.c
> +++ b/lib/eal/common/eal_common_dev.c
> @@ -385,19 +385,21 @@ local_dev_remove(struct rte_device *dev)
> {
> int ret;
>
> - if (dev->bus->unplug == NULL) {
> - EAL_LOG(ERR, "Function unplug not supported by bus (%s)",
> + if (dev->bus->unplug_device == NULL) {
> + EAL_LOG(ERR, "Function unplug_device not supported by bus (%s)",
> dev->bus->name);
> return -ENOTSUP;
> }
>
> - ret = dev->bus->unplug(dev);
> + ret = dev->bus->unplug_device(dev);
> if (ret) {
> EAL_LOG(ERR, "Driver cannot detach the device (%s)",
> dev->name);
> return (ret < 0) ? ret : -ENOENT;
> }
>
> + dev->driver = NULL;
> +
> return 0;
> }
>
> diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
> index 9711e6712b..fde55ff06d 100644
> --- a/lib/eal/include/bus_driver.h
> +++ b/lib/eal/include/bus_driver.h
> @@ -101,7 +101,7 @@ typedef int (*rte_bus_probe_device_t)(struct rte_driver *drv, struct rte_device
> * 0 on success.
> * !0 on error.
> */
> -typedef int (*rte_bus_unplug_t)(struct rte_device *dev);
> +typedef int (*rte_bus_unplug_device_t)(struct rte_device *dev);
>
> /**
> * Bus specific parsing function.
> @@ -323,7 +323,7 @@ struct rte_bus {
> rte_bus_find_device_t find_device; /**< Find a device on the bus */
> rte_bus_match_t match; /**< Check if driver matches device */
> rte_bus_probe_device_t probe_device; /**< Probe single device with driver */
> - rte_bus_unplug_t unplug; /**< Remove single device from driver */
> + rte_bus_unplug_device_t unplug_device; /**< Remove single device from driver */
> rte_bus_parse_t parse; /**< Parse a device name */
> rte_bus_dev_compare_t dev_compare; /**< Compare two device names */
> rte_bus_devargs_parse_t devargs_parse; /**< Parse bus devargs */
> --
> 2.53.0
>
^ permalink raw reply
* Re: [PATCH v2 01/10] bus: fix reference to plug callback
From: Bruce Richardson @ 2026-06-22 9:49 UTC (permalink / raw)
To: David Marchand; +Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal
In-Reply-To: <20260618152826.490569-2-david.marchand@redhat.com>
On Thu, Jun 18, 2026 at 05:28:16PM +0200, David Marchand wrote:
> Remove now unused typedef, update documentation
> and some log following the callback rename.
>
> Fixes: 76622feba9e6 ("bus: refactor device probe")
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> Changes since v1:
> - remove missed rte_bus_plug_t typedef,
>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply
* Re: [PATCH v2 02/10] dma/idxd: remove next pointer in bus specific device
From: Bruce Richardson @ 2026-06-22 9:48 UTC (permalink / raw)
To: David Marchand
Cc: dev, thomas, stephen, fengchengwen, longli, hemant.agrawal,
Kevin Laatz
In-Reply-To: <20260618152826.490569-3-david.marchand@redhat.com>
On Thu, Jun 18, 2026 at 05:28:17PM +0200, David Marchand wrote:
> The dma/idxd devices are now stored in a list of generic rte_device
> objects.
>
> Fixes: b4f0974a995b ("bus: factorize device list")
>
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
> drivers/dma/idxd/idxd_bus.c | 1 -
> 1 file changed, 1 deletion(-)
>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
^ permalink raw reply
* Re: [PATCH 3/3] ml/cnxk: updated checks for number of MRVL layers
From: Jerin Jacob @ 2026-06-22 9:30 UTC (permalink / raw)
To: Srikanth Yalavarthi; +Cc: dev, jerinj, sshankarnara, ptakkar, aprabhu
In-Reply-To: <20260609044202.936153-3-syalavarthi@marvell.com>
On Tue, Jun 9, 2026 at 10:12 AM Srikanth Yalavarthi
<syalavarthi@marvell.com> wrote:
>
> 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>
Series applied to dpdk-next-net-mrvl/for-main. Thanks
^ permalink raw reply
* Re: [PATCH 2/2] test/dma: add functions to verify zero and one fill
From: Bruce Richardson @ 2026-06-22 9:27 UTC (permalink / raw)
To: Tejasree Kondoj
Cc: Akhil Goyal, Chengwen Feng, Kevin Laatz, Vidya Sagar Velumuri,
Anoob Joseph, dev
In-Reply-To: <20260622030623.86094-3-ktejasree@marvell.com>
On Mon, Jun 22, 2026 at 08:36:23AM +0530, Tejasree Kondoj wrote:
> Add test cases to verify zero fill and one fill
>
> Signed-off-by: Vidya Sagar Velumuri <vvelumuri@marvell.com>
> ---
> app/test/test.h | 4 +++
> app/test/test_dmadev.c | 57 ++++++++++++++++++++++++------------------
> 2 files changed, 37 insertions(+), 24 deletions(-)
>
Not a bad idea. One piece of feedback inline below. Otherwise:
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
> diff --git a/app/test/test.h b/app/test/test.h
> index 1f12fc5397..5fc2d7d048 100644
> --- a/app/test/test.h
> +++ b/app/test/test.h
> @@ -28,6 +28,10 @@
>
> #include <rte_test.h>
>
> +#ifndef ARRAY_SIZE
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +#endif
> +
> #define TEST_ASSERT RTE_TEST_ASSERT
>
> #define TEST_ASSERT_EQUAL RTE_TEST_ASSERT_EQUAL
> diff --git a/app/test/test_dmadev.c b/app/test/test_dmadev.c
> index b30f2214e5..d4299e501d 100644
> --- a/app/test/test_dmadev.c
> +++ b/app/test/test_dmadev.c
> @@ -931,42 +931,51 @@ test_completion_handling(int16_t dev_id, uint16_t vchan)
> static int
> test_enqueue_fill(int16_t dev_id, uint16_t vchan)
> {
> + uint64_t pattern[3] = {0x0, 0xfedcba9876543210, 0xffffffffffffffff};
> const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
> + unsigned int i, j, k;
> struct rte_mbuf *dst;
> char *dst_data;
> - uint64_t pattern = 0xfedcba9876543210;
> - unsigned int i, j;
>
> dst = rte_pktmbuf_alloc(pool);
> if (dst == NULL)
> ERR_RETURN("Failed to allocate mbuf\n");
> dst_data = rte_pktmbuf_mtod(dst, char *);
>
> - for (i = 0; i < RTE_DIM(lengths); i++) {
> - /* reset dst_data */
> - memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> + for (k = 0; k < ARRAY_SIZE(pattern); k++) {
> + for (i = 0; i < RTE_DIM(lengths); i++) {
> + /* reset dst_data */
> + memset(dst_data, 0, rte_pktmbuf_data_len(dst));
> +
I don't think we should reset between each run, because of the zero-fill
operation, which we cannot detect if it runs properly. I'd suggest
therefore:
* zero the buffer outside the main loop
* Run the non-zero patterns first, checking each one, without reset
* Do the zero-pattern at the end, so we can see that zeroing works.
> + /* perform the fill operation */
> + int id = rte_dma_fill(dev_id, vchan, pattern[k],
> + rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> + if (id < 0) {
> + if (id == -ENOTSUP) {
> + rte_pktmbuf_free(dst);
> + return 0;
> + }
> + ERR_RETURN("Error with rte_dma_fill\n");
> + }
> + await_hw(dev_id, vchan);
>
> - /* perform the fill operation */
> - int id = rte_dma_fill(dev_id, vchan, pattern,
> - rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
> - if (id < 0)
> - ERR_RETURN("Error with rte_dma_fill\n");
> - await_hw(dev_id, vchan);
> + if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> + ERR_RETURN("Error: fill operation failed (length: %u)\n",
> + lengths[i]);
> + /* check the data from the fill operation is correct */
> + for (j = 0; j < lengths[i]; j++) {
> + char pat_byte = ((char *)&pattern[k])[j % 8];
>
> - if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
> - ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
> - /* check the data from the fill operation is correct */
> - for (j = 0; j < lengths[i]; j++) {
> - char pat_byte = ((char *)&pattern)[j % 8];
> - if (dst_data[j] != pat_byte)
> - ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> - lengths[i], dst_data[j], pat_byte);
> + if (dst_data[j] != pat_byte)
> + ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
> + lengths[i], dst_data[j], pat_byte);
> + }
> + /* check that the data after the fill operation was not written to */
> + for (; j < rte_pktmbuf_data_len(dst); j++)
> + if (dst_data[j] != 0)
> + ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> + lengths[i], dst_data[j], 0);
> }
> - /* check that the data after the fill operation was not written to */
> - for (; j < rte_pktmbuf_data_len(dst); j++)
> - if (dst_data[j] != 0)
> - ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
> - lengths[i], dst_data[j], 0);
> }
>
> rte_pktmbuf_free(dst);
> --
> 2.34.1
>
^ permalink raw reply
* [PATCH v5 23/23] net/sxe2: update sxe2 feature matrix docs
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-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 ++++++++++
doc/guides/nics/sxe2.rst | 164 ++++++++++++++++++++++++++++++
2 files changed, 220 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
diff --git a/doc/guides/nics/sxe2.rst b/doc/guides/nics/sxe2.rst
index 539072b076..06541bf66e 100644
--- a/doc/guides/nics/sxe2.rst
+++ b/doc/guides/nics/sxe2.rst
@@ -35,3 +35,167 @@ preventing unauthorized access to random physical memory.
This capability allows the PMD to coexist with kernel network interfaces
which remain functional, although they stop receiving unicast packets
as long as they share the same MAC address.
+
+Configuration
+-------------
+
+Runtime Configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+- ``Traffic Management Scheduling Levels``
+
+ The DPDK Traffic Management (rte_tm) APIs can be used to configure the Tx scheduler on the NIC.
+ The ``sched-layer-mode`` parameter can be used to set the number of scheduling levels
+ in the transmit scheduling hierarchy.
+ The provided value must be between 0 and 3.
+ If the value provided is greater than the number of levels supported by the HW,
+ the driver will use the hardware maximum value.
+
+- ``flow-duplicate-pattern`` parameter [int]
+
+ There are two options to choose:
+
+ - 0. Prevent insertion of flow rules with the same pattern items.
+ In this case, duplicate rules are rejected and error code EEXIST is returned.
+
+ - 1. Allow insertion of flow rules with the same pattern items.
+ In this case, the per-rule metadata flag ``switch_pattern_dup_allow`` is set
+ to instruct the hardware switch engine that rules with identical pattern
+ items are permitted.
+
+ This option only applies to the switch engine flow type.
+ For the Fnav flow engine type, duplicate rules are always rejected.
+
+ By default, the PMD will set this value to 1.
+
+- ``fnav-stat-type`` parameter [int]
+
+ This parameter controls the Fnav flow engine statistics type used
+ for flow rule hit counting (via ``rte_flow_query``).
+
+ - 1: Only count the number of packets.
+ - 2: Only count the number of bytes.
+ - 3: Count both packets and bytes (default).
+
+ Default value is 3 (count both packets and bytes).
+
+- ``drv-sw-stats`` parameter [int]
+
+ This parameter controls whether per-packet software statistics
+ (SW stats) are collected in the Rx data path.
+
+ Hardware packet statistic counters may be inaccurate for certain
+ packet types due to hardware design limitations.
+ When accuracy of Rx packet classification statistics is critical,
+ enabling this parameter allows the driver to accumulate statistics
+ in software as packets are received, providing an alternative
+ statistical path that bypasses hardware counter inaccuracies.
+
+ - 0: Disable software statistics collection (default).
+ The basic port statistics (``ipackets``, ``ibytes``) are reported
+ from the hardware counters.
+ - 1: Enable software statistics collection.
+ Per-packet software statistics are accumulated for unicast,
+ multicast, broadcast, and dropped packets in the Rx data path.
+
+ When enabled, the following extended statistics (xstats) are available:
+ ``rx_sw_unicast_packets``, ``rx_sw_multicast_packets``,
+ ``rx_sw_broadcast_packets``, ``rx_sw_drop_packets``,
+ and ``rx_sw_drop_bytes``.
+
+- ``no-sched-mode`` parameter [int]
+
+ This parameter enables non-scheduling mode (no-sched mode).
+ When enabled, the transmit path bypasses the hardware scheduling module
+ and packets are sent directly out through the port.
+ This results in lower transmit latency and higher throughput,
+ but Traffic Management (rte_tm) APIs are not supported in this mode.
+
+ - 0: Disable non-scheduling mode (default).
+ The transmit path goes through the hardware scheduling hierarchy.
+ Traffic Management (rte_tm) APIs can be used to configure the Tx scheduler.
+ - 1: Enable non-scheduling mode.
+ The transmit path bypasses the hardware scheduling module.
+ Packets are sent directly from the port at full speed without scheduling.
+ Traffic Management (rte_tm) APIs are not available in this mode.
+
+- ``rx-low-latency`` parameter [int]
+
+ This parameter controls the interrupt throttling (ITR) interval
+ for Rx queue interrupts.
+
+ When enabled, the driver sets a shorter interrupt coalescing timeout
+ (``SXE2_ITR_INTERVAL_LOW``, approximately 1 μs),
+ reducing the time between packet arrival and interrupt delivery to the CPU.
+ This lowers receive latency at the cost of increased CPU interrupt rate.
+
+ When disabled (default), the driver uses the normal interrupt throttling
+ interval (``SXE2_ITR_INTERVAL_NORMAL``, approximately 20 μs),
+ which reduces the CPU interrupt rate at the expense of higher receive latency.
+
+ - 0: Disable Rx low latency (default).
+ Normal interrupt throttling interval (~20 μs) is used.
+ - 1: Enable Rx low latency.
+ Low interrupt throttling interval (~1 μs) is used
+ for reduced receive latency.
+
+- ``function-flow-direct`` parameter [int]
+
+ This parameter controls whether flow rules from different functional units
+ (DPDK vs kernel driver) are isolated or combined when both drivers
+ control the same physical port.
+
+ When the DPDK PMD and the kernel network driver coexist on the same port,
+ flow rules may originate from either driver.
+ This parameter determines how the source VSI (Virtual Switch Interface)
+ of each flow rule is handled during hardware programming.
+
+ - 0 (default): Isolate flow rules between DPDK and kernel.
+ When ``flow_isolated`` is enabled (``rte_flow_isolate()`` called),
+ kernel-side flow rules take priority and DPDK-side flow rules are suppressed.
+ When ``flow_isolated`` is disabled, DPDK-side flow rules take priority
+ and kernel-side flow rules are suppressed.
+ Only one functional unit's flows are active at a time.
+
+ - 1: Allow direct flow rules from both DPDK and kernel simultaneously.
+ Both DPDK and kernel source VSIs are preserved in the hardware flow table.
+ Flow rules from both sides are programmed without isolation.
+
+ This option only applies to FNAV and ACL flow engine types
+ and does not apply to PF bond devices.
+
+Extended Statistics (xstats)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The PMD provides the following extended statistics (xstats) for detailed
+monitoring of receive-side packet classification and software-level accounting.
+The software statistics path is provided as a workaround for hardware
+counter inaccuracies on certain packet types --- it accumulates per-packet
+statistics directly in the Rx data path, ensuring that unicast, multicast,
+broadcast, and drop counts reflect the actual packets processed by the driver.
+
+Receive Software Statistics
+ These counters are collected in the Rx data path when ``drv-sw-stats=1``
+ is configured (see the ``drv-sw-stats`` devarg above).
+ When ``drv-sw-stats`` is disabled (default), these xstats report zero.
+
+ - ``rx_sw_unicast_packets``: Number of unicast packets received.
+ - ``rx_sw_multicast_packets``: Number of multicast packets received.
+ - ``rx_sw_broadcast_packets``: Number of broadcast packets received.
+ - ``rx_sw_drop_packets``: Number of packets dropped in the Rx data path.
+ - ``rx_sw_drop_bytes``: Number of bytes dropped in the Rx data path.
+
+ When ``drv-sw-stats`` is enabled, the basic counters ``ipackets`` and
+ ``ibytes`` (from ``rte_eth_stats``) also reflect the software-accumulated
+ packet and byte counts. Otherwise, they are reported from hardware counters.
+
+Fnav Flow Engine Statistics
+ The Fnav flow engine statistics type is controlled by the ``fnav-stat-type``
+ devarg (see above). Depending on the configuration:
+
+ - ``fnav-stat-type=1``: Only packet count is available.
+ - ``fnav-stat-type=2``: Only byte count is available.
+ - ``fnav-stat-type=3`` (default): Both packet and byte counts are available.
+
+ Flow query results (via ``rte_flow_query``) expose these per-flow counters
+ through the query API, not via xstats.
--
2.52.0
^ permalink raw reply related
* [PATCH v5 22/23] net/sxe2: add private devargs parsing
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
Introduce runtime private device arguments (devargs) support for the
sxe2 PMD. This allows users to customize driver behavior at startup
without recompiling the source code.
The parameters are parsed using the standard 'rte_kvargs' library during
the PCI/vdev probing phase. Documentation for these parameters is also
updated.
Signed-off-by: Jie Liu <liujie5@linkdatatechnology.com>
---
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 | 272 +++++++++++++++++++++++++++++--
drivers/net/sxe2/sxe2_ethdev.h | 6 +
drivers/net/sxe2/sxe2_flow.c | 9 +-
drivers/net/sxe2/sxe2_irq.c | 30 ++++
drivers/net/sxe2/sxe2_rx.c | 12 ++
9 files changed, 369 insertions(+), 16 deletions(-)
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 3fabf351af..03ef3b315d 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 d43473e083..c7cdde5f4f 100644
--- a/drivers/net/sxe2/sxe2_dump.c
+++ b/drivers/net/sxe2/sxe2_dump.c
@@ -186,6 +186,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)
@@ -272,6 +286,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 c140c26be1..ef68a28ed1 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -69,6 +69,15 @@ 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_NO_SCHED_MODE "no-sched-mode"
+#define SXE2_DEVARG_SCHED_LAYER_MODE "sched-layer-mode"
+#define SXE2_DEVARG_RX_LOW_LATENCY "rx-low-latency"
+
+#define SXE2_FLOW_DUP_PATTERN_DEFAULT 1
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,
@@ -965,6 +974,149 @@ sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev __rte_unused,
return ptypes;
}
+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;
+ unsigned long fnav_stat_type;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ fnav_stat_type = strtoul(value, &endptr, 10);
+ if (errno != 0 || endptr == value || *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 = (uint8_t)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;
+ unsigned long sched_layer_mode;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ sched_layer_mode = strtoul(value, &endptr, 10);
+ if (errno != 0 || endptr == value || *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 = (uint8_t)sched_layer_mode;
+ ret = 0;
+l_end:
+ return ret;
+}
+static int32_t sxe2_parse_no_sched_mode(const char *key, const char *value, void *args)
+{
+ int32_t ret = -EINVAL;
+ uint8_t *num = (uint8_t *)args;
+ unsigned long no_sched_mode;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ no_sched_mode = strtoul(value, &endptr, 10);
+ if (errno != 0 || endptr == value || *endptr != '\0') {
+ PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.",
+ key, value);
+ goto l_end;
+ }
+ if (no_sched_mode != 1) {
+ PMD_LOG_ERR(INIT, "%s: \"%s\" != 1.",
+ key, value);
+ goto l_end;
+ }
+ *num = (uint8_t)no_sched_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 = (uint8_t)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;
+ unsigned long bool_val;
+ char *endptr = NULL;
+
+ if (value == NULL || args == NULL) {
+ ret = 0;
+ goto l_end;
+ }
+ errno = 0;
+ bool_val = strtoul(value, &endptr, 10);
+ if (errno != 0 || endptr == value || *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 = (uint8_t)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)
{
@@ -1032,6 +1184,65 @@ 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();
+
+ adapter->devargs.flow_dup_pattern_mode = SXE2_FLOW_DUP_PATTERN_DEFAULT;
+
+ 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_NO_SCHED_MODE,
+ &sxe2_parse_no_sched_mode,
+ &adapter->devargs.no_sched_mode);
+ if (ret) {
+ PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse no sched mode, 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;
@@ -1584,6 +1795,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;
@@ -1646,18 +1888,6 @@ static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev)
return ret;
}
-static int32_t sxe2_args_parse(struct rte_eth_dev *dev,
- __rte_unused struct sxe2_dev_kvargs_info *kvargs)
-{
- struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
- int32_t ret = 0;
- PMD_INIT_FUNC_TRACE();
-
- adapter->devargs.flow_dup_pattern_mode = SXE2_FLOW_DUP_PATTERN_DEFAULT;
-
- return ret;
-}
-
static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
struct sxe2_dev_kvargs_info *kvargs)
{
@@ -1680,7 +1910,7 @@ static int32_t sxe2_dev_init(struct rte_eth_dev *dev,
ret = sxe2_args_parse(dev, kvargs);
if (ret) {
- PMD_LOG_ERR(INIT, "Failed to parse args, ret=[%d]", ret);
+ PMD_LOG_ERR(INIT, "Failed to parse devargs, ret=%d", ret);
goto l_end;
}
@@ -1750,6 +1980,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);
@@ -1773,6 +2009,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:
@@ -1818,6 +2056,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;
@@ -2123,6 +2362,13 @@ RTE_INIT(rte_sxe2_pmd_init)
RTE_PMD_EXPORT_NAME(net_sxe2);
RTE_PMD_REGISTER_PCI_TABLE(net_sxe2, pci_id_sxe2_tbl);
RTE_PMD_REGISTER_KMOD_DEP(net_sxe2, "* sxe2");
+RTE_PMD_REGISTER_PARAM_STRING(net_sxe2,
+ "flow-duplicate-pattern=<0|1> "
+ "function-flow-direct=<0|1> "
+ "fnav-stat-type=<1|2|3> "
+ "no-sched-mode=<0|1> "
+ "sched-layer-mode=<0-3> "
+ "rx-low-latency=<0|1>");
RTE_LOG_REGISTER_SUFFIX(sxe2_log_init, init, NOTICE);
RTE_LOG_REGISTER_SUFFIX(sxe2_log_driver, driver, NOTICE);
diff --git a/drivers/net/sxe2/sxe2_ethdev.h b/drivers/net/sxe2/sxe2_ethdev.h
index a68b95c0d0..c54e8a435e 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -310,6 +310,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;
@@ -331,6 +336,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;
diff --git a/drivers/net/sxe2/sxe2_flow.c b/drivers/net/sxe2/sxe2_flow.c
index 63cfc36968..1aa5813ee4 100644
--- a/drivers/net/sxe2/sxe2_flow.c
+++ b/drivers/net/sxe2/sxe2_flow.c
@@ -762,6 +762,7 @@ static int32_t sxe2_flow_validate_with_flow(struct rte_eth_dev *dev,
const struct rte_flow_action actions[],
struct rte_flow_error *error)
{
+ struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev);
int32_t ret = 0;
struct sxe2_flow *flow = NULL;
@@ -804,9 +805,11 @@ static int32_t sxe2_flow_validate_with_flow(struct rte_eth_dev *dev,
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.");
+ rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+ adapter->devargs.flow_dup_pattern_mode ?
+ "Duplicate flow pattern." :
+ "Duplicate flow pattern is not allowed.");
+ PMD_LOG_ERR(DRV, "Duplicate flow pattern.");
goto l_end;
}
l_end:
diff --git a/drivers/net/sxe2/sxe2_irq.c b/drivers/net/sxe2/sxe2_irq.c
index d8e0b19463..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)
diff --git a/drivers/net/sxe2/sxe2_rx.c b/drivers/net/sxe2/sxe2_rx.c
index 820d4f0620..d700c60083 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)
--
2.52.0
^ permalink raw reply related
* [PATCH v5 21/23] common/sxe2: add callback for memory event handling
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-1-liujie5@linkdatatechnology.com>
From: Jie Liu <liujie5@linkdatatechnology.com>
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.
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 +-
3 files changed, 113 insertions(+), 1 deletion(-)
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)
--
2.52.0
^ permalink raw reply related
* [PATCH v5 20/23] net/sxe2: add mbuf validation in Tx debug mode
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-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 | 1 +
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, 640 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..2405213809 100644
--- a/drivers/net/sxe2/meson.build
+++ b/drivers/net/sxe2/meson.build
@@ -78,4 +78,5 @@ 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 82b2e4fb7c..2081b96499 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
* [PATCH v5 19/23] net/sxe2: implement private dump info
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-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 | 287 ++++++++++++++++++++++++++++
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, 306 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..d43473e083
--- /dev/null
+++ b/drivers/net/sxe2/sxe2_dump.c
@@ -0,0 +1,287 @@
+/* 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 -- no_sched_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.no_sched_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 5bb57331ed..c140c26be1 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -37,6 +37,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"
@@ -195,6 +196,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 15b839bb74..f32318b731 100644
--- a/drivers/net/sxe2/sxe2_ethdev_repr.c
+++ b/drivers/net/sxe2/sxe2_ethdev_repr.c
@@ -11,6 +11,7 @@
#include "sxe2_txrx.h"
#include "sxe2_switchdev.h"
#include "sxe2_mp.h"
+#include "sxe2_dump.h"
#include "sxe2_stats.h"
#include "sxe2_flow.h"
@@ -236,6 +237,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 v5 18/23] net/sxe2: support SFP module info and EEPROM access
From: liujie5 @ 2026-06-22 9:27 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-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 3e0b70ab02..3fabf351af 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 eb0d09eb39..5bb57331ed 100644
--- a/drivers/net/sxe2/sxe2_ethdev.c
+++ b/drivers/net/sxe2/sxe2_ethdev.c
@@ -40,6 +40,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
@@ -123,6 +124,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,
@@ -187,6 +192,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)
@@ -292,6 +300,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 0c7fc56ec5..a68b95c0d0 100644
--- a/drivers/net/sxe2/sxe2_ethdev.h
+++ b/drivers/net/sxe2/sxe2_ethdev.h
@@ -274,6 +274,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 v5 17/23] common/sxe2: add shared SFP module definitions
From: liujie5 @ 2026-06-22 9:26 UTC (permalink / raw)
To: stephen; +Cc: dev, Jie Liu
In-Reply-To: <20260622092324.3091185-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
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