* [PATCH v10 08/21] net/txgbe: fix link flow control registers for Amber-Lite
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 05/21] net/txgbe: fix inaccuracy in Tx rate limiting
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 06/21] net/txgbe: fix link status check condition
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 04/21] net/ngbe: fix VF promiscuous and allmulticast
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 01/21] net/txgbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu, Ferruh Yigit
In-Reply-To: <20260624115254.20348-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 v10 02/21] net/ngbe: remove duplicate xstats counters
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 03/21] net/ngbe: add missing CDR config for YT PHY
From: Zaiyu Wang @ 2026-06-24 11:52 UTC (permalink / raw)
To: dev; +Cc: Zaiyu Wang, stable, Jiawen Wu
In-Reply-To: <20260624115254.20348-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 v10 00/21] Wangxun Fixes
From: Zaiyu Wang @ 2026-06-24 11:52 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.
---
v10:
- Fixed compilation error on clang
- Renamed unprefixed symbols
---
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 | 3746 +++++++++++++++++++++
drivers/net/txgbe/base/txgbe_e56.h | 1778 ++++++++++
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 | 111 +-
drivers/net/txgbe/txgbe_rxtx.h | 38 +-
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 17 +-
26 files changed, 9464 insertions(+), 446 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 v9 07/21] net/txgbe: fix Tx desc free logic
From: Zaiyu Wang @ 2026-06-24 11:47 UTC (permalink / raw)
To: 'Stephen Hemminger'; +Cc: dev
In-Reply-To: <20260623095047.7d12d5d4@phoenix.local>
> This will fail build on clang since txq->headwb_mem is declared as volatile not _Atomic
type.
>
> Please fix, and resubmit both patch series.
Hi Stephen,
Thank you for pointing this out. I apologize for the oversight - I failed to pay proper
attention to the failure from ci/github-robot: build, and mistakenly focused only on the
ci/Intel-compilation and others.
This error has been fixed in v10. Additionally, the unprefixed symbols that did not meet
the naming conventions have been renamed with the txgbe_ prefix.
Our other patch series will be resubmitted later. The code for VF sensing PF down differs
from our OOT driver, and its functionality requires further validation before submission.
^ permalink raw reply
* [PATCH] build: use native Linux strlcpy when available
From: Bruce Richardson @ 2026-06-24 11:35 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson
Glibc added the strlcpy and strlcat functions to version 2.38, meaning
they are natively available in modern linux distros without having to
use libbsd, or a dpdk-specific fallback. Therefore, we adjust our
fallback detection logic to have meson check for the presence of these
functions before checking if we actually need libbsd. Then in
rte_string_fns.h we rework our macros a little for setting the fallback:
1. If libbsd is to be used, just always include it as a standalone
block. With new meson logic, we only use it if we have to, even if
present.
2. For BSD, configure fallback functions only if __BSD_VISIBLE is not
defined, otherwise just use native fns.
3. Otherwise for Linux and Windows, configure the fallback functions if
meson has not set RTE_HAS_STRLCPY.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
config/meson.build | 14 ++++++++++----
lib/eal/include/rte_string_fns.h | 18 +++++++-----------
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/config/meson.build b/config/meson.build
index d7f5e55c18..0049cd3807 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -266,10 +266,16 @@ if libarchive.found()
dpdk_conf.set('RTE_HAS_LIBARCHIVE', 1)
endif
-# check for libbsd
-libbsd = dependency('libbsd', required: false, method: 'pkg-config')
-if libbsd.found()
- dpdk_conf.set('RTE_USE_LIBBSD', 1)
+# check for strlcpy: first in native libc, then via libbsd as fallback
+if cc.has_function('strlcpy', prefix: '#include <string.h>')
+ dpdk_conf.set('RTE_HAS_STRLCPY', 1)
+ libbsd = dependency('', required: false) # empty not-found dependency
+else
+ libbsd = dependency('libbsd', required: false, method: 'pkg-config')
+ if libbsd.found()
+ dpdk_conf.set('RTE_USE_LIBBSD', 1)
+ dpdk_conf.set('RTE_HAS_STRLCPY', 1)
+ endif
endif
jansson_dep = dependency('jansson', required: false, method: 'pkg-config')
diff --git a/lib/eal/include/rte_string_fns.h b/lib/eal/include/rte_string_fns.h
index 3713c94acb..4fb2a6c1ce 100644
--- a/lib/eal/include/rte_string_fns.h
+++ b/lib/eal/include/rte_string_fns.h
@@ -14,6 +14,9 @@
#include <ctype.h>
#include <stdio.h>
#include <string.h>
+#ifdef RTE_USE_LIBBSD
+#include <bsd/string.h>
+#endif
#include <rte_common.h>
#include <rte_compat.h>
@@ -81,23 +84,16 @@ rte_strlcat(char *dst, const char *src, size_t size)
}
#endif
-/* pull in a strlcpy function */
+/* provide strlcpy/strlcat aliases where not natively available */
#ifdef RTE_EXEC_ENV_FREEBSD
#ifndef __BSD_VISIBLE /* non-standard functions are hidden */
#define strlcpy(dst, src, size) rte_strlcpy(dst, src, size)
#define strlcat(dst, src, size) rte_strlcat(dst, src, size)
-#endif
-
-#else /* non-BSD platforms */
-#ifdef RTE_USE_LIBBSD
-#include <bsd/string.h>
-
-#else /* no BSD header files, create own */
+#endif /* __BSD_VISIBLE */
+#elif !defined(RTE_HAS_STRLCPY)
#define strlcpy(dst, src, size) rte_strlcpy(dst, src, size)
#define strlcat(dst, src, size) rte_strlcat(dst, src, size)
-
-#endif /* RTE_USE_LIBBSD */
-#endif /* FREEBSD */
+#endif /* RTE_EXEC_ENV_FREEBSD */
#ifdef __cplusplus
extern "C" {
--
2.53.0
^ permalink raw reply related
* [PATCH v4 12/12] bus/vmbus: support unplug
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
Add .unplug callback to handle driver removal, device unmapping, and
interrupt cleanup. This enables use of the generic bus cleanup helper.
The cleanup function was already performing these operations, so it
seems safe to expose them through the unplug operation.
Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
doc/guides/rel_notes/release_26_07.rst | 4 +++
drivers/bus/vmbus/vmbus_common.c | 41 ++++++++++++--------------
2 files changed, 23 insertions(+), 22 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_07.rst b/doc/guides/rel_notes/release_26_07.rst
index 5d7aa8d1bf..55d3b44527 100644
--- a/doc/guides/rel_notes/release_26_07.rst
+++ b/doc/guides/rel_notes/release_26_07.rst
@@ -114,6 +114,10 @@ New Features
Added no-IOMMU mode for devices without or not enabling IOMMU/SVA.
+* **Added unplug operation support to VMBUS bus.**
+
+ Implemented device unplug operation to allow runtime removal of VMBUS devices.
+
* **Added selective Rx in ethdev API.**
Some parts of packets may be discarded in Rx
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index a6e3a24a7c..cd6e851e4c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,34 +144,29 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(struct rte_bus *bus)
+vmbus_unplug_device(struct rte_device *rte_dev)
{
- struct rte_vmbus_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, bus) {
- const struct rte_vmbus_driver *drv;
- int ret;
-
- if (!rte_dev_is_probed(&dev->device))
- continue;
- drv = RTE_BUS_DRIVER(dev->device.driver, *drv);
- if (drv->remove == NULL)
- continue;
+ const struct rte_vmbus_driver *drv = RTE_BUS_DRIVER(rte_dev->driver, *drv);
+ struct rte_vmbus_device *dev = RTE_BUS_DEVICE(rte_dev, *dev);
+ int ret = 0;
+ if (drv->remove != NULL) {
ret = drv->remove(dev);
if (ret < 0)
- error = -1;
+ return ret;
+ }
- rte_vmbus_unmap_device(dev);
- rte_intr_instance_free(dev->intr_handle);
+ rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
+ dev->intr_handle = NULL;
- dev->device.driver = NULL;
- rte_bus_remove_device(bus, &dev->device);
- free(dev);
- }
+ return 0;
+}
- return error;
+static void
+vmbus_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vmbus_device));
}
static int
@@ -222,10 +217,12 @@ rte_vmbus_unregister(struct rte_vmbus_driver *driver)
struct rte_bus rte_vmbus_bus = {
.scan = rte_vmbus_scan,
.probe = rte_bus_generic_probe,
- .cleanup = rte_vmbus_cleanup,
+ .free_device = vmbus_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = vmbus_bus_match,
.probe_device = vmbus_probe_device,
+ .unplug_device = vmbus_unplug_device,
.parse = vmbus_parse,
.dev_compare = vmbus_dev_compare,
};
--
2.54.0
^ permalink raw reply related
* [PATCH v4 11/12] bus/vmbus: store name in bus specific device
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
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>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 10 +++-------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/drivers/bus/vmbus/bus_vmbus_driver.h b/drivers/bus/vmbus/bus_vmbus_driver.h
index 888d856141..706ff1fcf5 100644
--- a/drivers/bus/vmbus/bus_vmbus_driver.h
+++ b/drivers/bus/vmbus/bus_vmbus_driver.h
@@ -38,6 +38,7 @@ enum hv_uio_map {
*/
struct rte_vmbus_device {
struct rte_device device; /**< Inherit core device */
+ char name[RTE_DEV_NAME_MAX_LEN]; /**< VMBUS device name */
rte_uuid_t device_id; /**< VMBUS device id */
rte_uuid_t class_id; /**< VMBUS device type */
uint32_t relid; /**< id for primary */
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 77d904ad6d..779ea50b92 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -280,15 +280,14 @@ vmbus_scan_one(const char *name)
char filename[PATH_MAX];
char dirname[PATH_MAX];
unsigned long tmp;
- char *dev_name;
dev = calloc(1, sizeof(*dev));
if (dev == NULL)
return -1;
- dev->device.name = dev_name = strdup(name);
- if (!dev->device.name)
+ if (rte_strscpy(dev->name, name, sizeof(dev->name)) < 0)
goto error;
+ dev->device.name = dev->name;
/* sysfs base directory
* /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df
@@ -305,7 +304,6 @@ vmbus_scan_one(const char *name)
/* skip non-network devices */
if (rte_uuid_compare(dev->class_id, vmbus_nic_uuid) != 0) {
- free(dev_name);
free(dev);
return 0;
}
@@ -330,7 +328,7 @@ vmbus_scan_one(const char *name)
dev->monitor_id = UINT8_MAX;
}
- dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev_name);
+ dev->device.devargs = rte_bus_find_devargs(&rte_vmbus_bus, dev->name);
dev->device.numa_node = SOCKET_ID_ANY;
if (vmbus_use_numa(dev)) {
@@ -360,7 +358,6 @@ vmbus_scan_one(const char *name)
} else { /* already registered */
VMBUS_LOG(NOTICE,
"%s already registered", name);
- free(dev_name);
free(dev);
}
return 0;
@@ -371,7 +368,6 @@ vmbus_scan_one(const char *name)
error:
VMBUS_LOG(DEBUG, "failed");
- free(dev_name);
free(dev);
return -1;
}
--
2.54.0
^ permalink raw reply related
* [PATCH v4 10/12] bus: implement cleanup in EAL
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Sachin Saxena, Rosen Xu,
Chenbo Xia, Nipun Gupta, Tomasz Duszynski, Wei Hu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
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>
---
Changes since v1:
- dropped hack on using free() and the check in RTE_REGISTER_BUS,
---
drivers/bus/auxiliary/auxiliary_common.c | 28 ++++---------------
drivers/bus/dpaa/dpaa_bus.c | 4 +--
drivers/bus/fslmc/fslmc_bus.c | 2 +-
drivers/bus/ifpga/ifpga_bus.c | 32 ++++------------------
drivers/bus/pci/pci_common.c | 29 +++++---------------
drivers/bus/platform/platform.c | 20 ++++----------
drivers/bus/uacce/uacce.c | 28 ++++---------------
drivers/bus/vdev/vdev.c | 26 +++++++-----------
drivers/bus/vmbus/vmbus_common.c | 6 ++---
lib/eal/common/eal_common_bus.c | 33 ++++++++++++++++++++++-
lib/eal/include/bus_driver.h | 34 +++++++++++++++++++++++-
11 files changed, 107 insertions(+), 135 deletions(-)
diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c
index 10f466e57a..80b90a4961 100644
--- a/drivers/bus/auxiliary/auxiliary_common.c
+++ b/drivers/bus/auxiliary/auxiliary_common.c
@@ -179,29 +179,10 @@ rte_auxiliary_unregister(struct rte_auxiliary_driver *driver)
rte_bus_remove_driver(&auxiliary_bus, &driver->driver);
}
-static int
-auxiliary_cleanup(void)
+static void
+auxiliary_free_device(struct rte_device *dev)
{
- struct rte_auxiliary_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &auxiliary_bus) {
- int ret;
-
- 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;
+ free(RTE_BUS_DEVICE(dev, struct rte_auxiliary_device));
}
static int
@@ -247,7 +228,8 @@ auxiliary_get_iommu_class(void)
struct rte_bus auxiliary_bus = {
.scan = auxiliary_scan,
.probe = rte_bus_generic_probe,
- .cleanup = auxiliary_cleanup,
+ .free_device = auxiliary_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = auxiliary_bus_match,
.probe_device = auxiliary_probe_device,
diff --git a/drivers/bus/dpaa/dpaa_bus.c b/drivers/bus/dpaa/dpaa_bus.c
index ee467b94d5..54779f82f7 100644
--- a/drivers/bus/dpaa/dpaa_bus.c
+++ b/drivers/bus/dpaa/dpaa_bus.c
@@ -807,12 +807,12 @@ dpaa_bus_probe_device(struct rte_driver *drv, struct rte_device *dev)
}
static int
-dpaa_bus_cleanup(void)
+dpaa_bus_cleanup(struct rte_bus *bus)
{
struct rte_dpaa_device *dev;
BUS_INIT_FUNC_TRACE();
- RTE_BUS_FOREACH_DEV(dev, &rte_dpaa_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_dpaa_driver *drv;
int ret = 0;
diff --git a/drivers/bus/fslmc/fslmc_bus.c b/drivers/bus/fslmc/fslmc_bus.c
index dca4c5b182..1a0eca30b4 100644
--- a/drivers/bus/fslmc/fslmc_bus.c
+++ b/drivers/bus/fslmc/fslmc_bus.c
@@ -436,7 +436,7 @@ fslmc_bus_match(const struct rte_driver *drv, const struct rte_device *dev)
}
static int
-rte_fslmc_close(void)
+rte_fslmc_close(struct rte_bus *bus __rte_unused)
{
int ret = 0;
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 7e2e2efce0..79d1c3778f 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -298,33 +298,10 @@ ifpga_unplug_device(struct rte_device *dev)
return 0;
}
-/*
- * Cleanup the content of the Intel FPGA bus, and call the remove() function
- * for all registered devices.
- */
-static int
-ifpga_cleanup(void)
+static void
+ifpga_free_device(struct rte_device *dev)
{
- struct rte_afu_device *afu_dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(afu_dev, &rte_ifpga_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&afu_dev->device)) {
- ret = ifpga_unplug_device(&afu_dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(afu_dev->device.devargs);
- rte_bus_remove_device(&rte_ifpga_bus, &afu_dev->device);
- free(afu_dev);
- }
-
- return error;
+ free(RTE_BUS_DEVICE(dev, struct rte_afu_device));
}
static int
@@ -374,7 +351,8 @@ ifpga_parse(const char *name, void *addr)
static struct rte_bus rte_ifpga_bus = {
.scan = ifpga_scan,
.probe = rte_bus_generic_probe,
- .cleanup = ifpga_cleanup,
+ .free_device = ifpga_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = ifpga_bus_match,
.probe_device = ifpga_probe_device,
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bf4822f7ec..0f635e1537 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -317,29 +317,11 @@ pci_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-pci_cleanup(void)
+static void
+pci_free_device(struct rte_device *dev)
{
- struct rte_pci_device *dev;
- int error = 0;
-
- RTE_BUS_FOREACH_DEV(dev, &rte_pci_bus) {
- int ret = 0;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = pci_unplug_device(&dev->device);
- if (ret < 0) {
- rte_errno = errno;
- error = -1;
- }
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_pci_bus, &dev->device);
- pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
- }
-
- return error;
+ struct rte_pci_device *pdev = RTE_BUS_DEVICE(dev, *pdev);
+ pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
}
/* dump one device */
@@ -743,7 +725,8 @@ struct rte_bus rte_pci_bus = {
.allow_multi_probe = true,
.scan = rte_pci_scan,
.probe = rte_bus_generic_probe,
- .cleanup = pci_cleanup,
+ .free_device = pci_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = pci_bus_match,
.probe_device = pci_probe_device,
diff --git a/drivers/bus/platform/platform.c b/drivers/bus/platform/platform.c
index 5b3c78a505..90d865a8df 100644
--- a/drivers/bus/platform/platform.c
+++ b/drivers/bus/platform/platform.c
@@ -491,26 +491,17 @@ platform_bus_get_iommu_class(void)
return RTE_IOVA_DC;
}
-static int
-platform_bus_cleanup(void)
+static void
+platform_free_device(struct rte_device *dev)
{
- 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);
- free(pdev);
- }
-
- return 0;
+ free(RTE_BUS_DEVICE(dev, struct rte_platform_device));
}
static struct rte_bus platform_bus = {
.scan = platform_bus_scan,
.probe = rte_bus_generic_probe,
+ .free_device = platform_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.find_device = rte_bus_generic_find_device,
.match = platform_bus_match,
.probe_device = platform_bus_probe_device,
@@ -520,7 +511,6 @@ static struct rte_bus platform_bus = {
.dma_unmap = platform_bus_dma_unmap,
.get_iommu_class = platform_bus_get_iommu_class,
.dev_iterate = rte_bus_generic_dev_iterate,
- .cleanup = platform_bus_cleanup,
};
RTE_REGISTER_BUS(platform, platform_bus);
diff --git a/drivers/bus/uacce/uacce.c b/drivers/bus/uacce/uacce.c
index bfe1f26557..99a6fb314d 100644
--- a/drivers/bus/uacce/uacce.c
+++ b/drivers/bus/uacce/uacce.c
@@ -402,29 +402,10 @@ uacce_unplug_device(struct rte_device *rte_dev)
return 0;
}
-static int
-uacce_cleanup(void)
+static void
+uacce_free_device(struct rte_device *dev)
{
- struct rte_uacce_device *dev;
- int error = 0;
-
- 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 error;
+ free(RTE_BUS_DEVICE(dev, struct rte_uacce_device));
}
static int
@@ -551,7 +532,8 @@ rte_uacce_unregister(struct rte_uacce_driver *driver)
static struct rte_bus uacce_bus = {
.scan = uacce_scan,
.probe = rte_bus_generic_probe,
- .cleanup = uacce_cleanup,
+ .free_device = uacce_free_device,
+ .cleanup = rte_bus_generic_cleanup,
.match = uacce_bus_match,
.probe_device = uacce_probe_device,
.unplug_device = uacce_unplug_device,
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 7e94f86e28..02d719a44d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -548,26 +548,19 @@ vdev_scan(void)
return 0;
}
+static void
+vdev_free_device(struct rte_device *dev)
+{
+ free(RTE_BUS_DEVICE(dev, struct rte_vdev_device));
+}
+
static int
-vdev_cleanup(void)
+vdev_cleanup(struct rte_bus *bus)
{
- struct rte_vdev_device *dev;
- int error = 0;
+ int error;
rte_spinlock_recursive_lock(&vdev_device_list_lock);
- RTE_BUS_FOREACH_DEV(dev, &rte_vdev_bus) {
- int ret;
-
- if (rte_dev_is_probed(&dev->device)) {
- ret = vdev_unplug_device(&dev->device);
- if (ret < 0)
- error = -1;
- }
-
- rte_devargs_remove(dev->device.devargs);
- rte_bus_remove_device(&rte_vdev_bus, &dev->device);
- free(dev);
- }
+ error = rte_bus_generic_cleanup(bus);
rte_spinlock_recursive_unlock(&vdev_device_list_lock);
return error;
@@ -608,6 +601,7 @@ vdev_get_iommu_class(void)
static struct rte_bus rte_vdev_bus = {
.scan = vdev_scan,
.probe = rte_bus_generic_probe,
+ .free_device = vdev_free_device,
.cleanup = vdev_cleanup,
.find_device = vdev_find_device,
.match = vdev_bus_match,
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index bfb45e963c..a6e3a24a7c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -144,12 +144,12 @@ rte_vmbus_probe(void)
}
static int
-rte_vmbus_cleanup(void)
+rte_vmbus_cleanup(struct rte_bus *bus)
{
struct rte_vmbus_device *dev;
int error = 0;
- RTE_BUS_FOREACH_DEV(dev, &rte_vmbus_bus) {
+ RTE_BUS_FOREACH_DEV(dev, bus) {
const struct rte_vmbus_driver *drv;
int ret;
@@ -167,7 +167,7 @@ rte_vmbus_cleanup(void)
rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
- rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
+ rte_bus_remove_device(bus, &dev->device);
free(dev);
}
diff --git a/lib/eal/common/eal_common_bus.c b/lib/eal/common/eal_common_bus.c
index ca13ccce5b..9ba23516ee 100644
--- a/lib/eal/common/eal_common_bus.c
+++ b/lib/eal/common/eal_common_bus.c
@@ -124,6 +124,37 @@ rte_bus_generic_probe(struct rte_bus *bus)
return (probed && probed == failed) ? -1 : 0;
}
+/*
+ * Generic cleanup function for buses.
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ */
+RTE_EXPORT_INTERNAL_SYMBOL(rte_bus_generic_cleanup)
+int
+rte_bus_generic_cleanup(struct rte_bus *bus)
+{
+ struct rte_device *dev;
+ int error = 0;
+
+ RTE_VERIFY(bus->free_device);
+ RTE_VERIFY(bus->unplug_device);
+
+ while ((dev = TAILQ_FIRST(&bus->device_list)) != NULL) {
+ if (rte_dev_is_probed(dev)) {
+ if (bus->unplug_device && bus->unplug_device(dev) < 0) {
+ rte_errno = errno;
+ error = -1;
+ }
+ }
+
+ rte_devargs_remove(dev->devargs);
+ rte_bus_remove_device(bus, dev);
+ bus->free_device(dev);
+ }
+
+ return error;
+}
+
/* Probe all devices of all buses */
RTE_EXPORT_SYMBOL(rte_bus_probe)
int
@@ -164,7 +195,7 @@ eal_bus_cleanup(void)
TAILQ_FOREACH(bus, &rte_bus_list, next) {
if (bus->cleanup == NULL)
continue;
- if (bus->cleanup() != 0)
+ if (bus->cleanup(bus) != 0)
ret = -1;
}
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index fde55ff06d..4f6521c87f 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -226,17 +226,31 @@ typedef int (*rte_bus_hot_unplug_handler_t)(struct rte_device *dev);
*/
typedef int (*rte_bus_sigbus_handler_t)(const void *failure_addr);
+/**
+ * Free a bus-specific device structure.
+ *
+ * @param dev
+ * Device pointer.
+ */
+typedef void (*rte_bus_free_device_t)(struct rte_device *dev);
+
/**
* Implementation specific cleanup function which is responsible for cleaning up
* devices on that bus with applicable drivers.
*
+ * The cleanup operation is the counterpart to scan, removing all devices added
+ * during scan.
+ *
* This is called while iterating over each registered bus.
*
+ * @param bus
+ * Pointer to the bus to cleanup.
+ *
* @return
* 0 for successful cleanup
* !0 for any error during cleanup
*/
-typedef int (*rte_bus_cleanup_t)(void);
+typedef int (*rte_bus_cleanup_t)(struct rte_bus *bus);
/**
* Check if a driver matches a device.
@@ -336,6 +350,7 @@ struct rte_bus {
/**< handle hot-unplug failure on the bus */
rte_bus_sigbus_handler_t sigbus_handler;
/**< handle sigbus error on the bus */
+ rte_bus_free_device_t free_device; /**< Free bus-specific device */
rte_bus_cleanup_t cleanup; /**< Cleanup devices on bus */
RTE_TAILQ_HEAD(, rte_device) device_list; /**< List of devices on the bus */
RTE_TAILQ_HEAD(, rte_driver) driver_list; /**< List of drivers on the bus */
@@ -624,6 +639,23 @@ struct rte_driver *rte_bus_find_driver(const struct rte_bus *bus, const struct r
__rte_internal
int rte_bus_generic_probe(struct rte_bus *bus);
+/**
+ * Generic cleanup function for buses.
+ *
+ * Iterates through all devices on the bus, unplugs probed devices,
+ * removes devargs, removes devices from the bus list, and frees device structures.
+ *
+ * This function can be used by buses that don't require special cleanup
+ * logic and just need the standard device cleanup sequence.
+ *
+ * @param bus
+ * Pointer to the bus to cleanup.
+ * @return
+ * 0 on success, -1 if any errors occurred during cleanup.
+ */
+__rte_internal
+int rte_bus_generic_cleanup(struct rte_bus *bus);
+
#ifdef __cplusplus
}
#endif
--
2.54.0
^ permalink raw reply related
* [PATCH v4 09/12] bus: align unplug with device probe
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Parav Pandit, Xueming Li, Nipun Gupta,
Nikhil Agarwal, Sachin Saxena, Rosen Xu, Chenbo Xia,
Tomasz Duszynski
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
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>
---
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 af77d69ef6..7e2e2efce0 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -279,6 +279,25 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
return ret;
}
+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.
@@ -290,52 +309,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)
{
@@ -387,7 +378,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.54.0
^ permalink raw reply related
* [PATCH v4 08/12] bus/ifpga: allocate interrupt during probing
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Rosen Xu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/bus/ifpga/ifpga_bus.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/drivers/bus/ifpga/ifpga_bus.c b/drivers/bus/ifpga/ifpga_bus.c
index 2c22329f65..af77d69ef6 100644
--- a/drivers/bus/ifpga/ifpga_bus.c
+++ b/drivers/bus/ifpga/ifpga_bus.c
@@ -144,14 +144,6 @@ ifpga_scan_one(struct rte_rawdev *rawdev,
afu_dev->id.uuid.uuid_high = 0;
afu_dev->id.port = afu_pr_conf.afu_id.port;
- /* Allocate interrupt instance */
- afu_dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (afu_dev->intr_handle == NULL) {
- IFPGA_BUS_ERR("Failed to allocate intr handle");
- goto end;
- }
-
if (rawdev->dev_ops && rawdev->dev_ops->dev_info_get)
rawdev->dev_ops->dev_info_get(rawdev, afu_dev, sizeof(*afu_dev));
@@ -177,10 +169,7 @@ ifpga_scan_one(struct rte_rawdev *rawdev,
end:
rte_kvargs_free(kvlist);
free(path);
- if (afu_dev) {
- rte_intr_instance_free(afu_dev->intr_handle);
- free(afu_dev);
- }
+ free(afu_dev);
return NULL;
}
@@ -272,8 +261,22 @@ ifpga_probe_device(struct rte_driver *drv, struct rte_device *dev)
{
struct rte_afu_device *afu_dev = RTE_BUS_DEVICE(dev, *afu_dev);
struct rte_afu_driver *afu_drv = RTE_BUS_DRIVER(drv, *afu_drv);
+ int ret;
+
+ afu_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (afu_dev->intr_handle == NULL) {
+ IFPGA_BUS_ERR("Failed to allocate intr handle");
+ return -ENOMEM;
+ }
+
+ ret = afu_drv->probe(afu_dev);
+ if (ret != 0) {
+ rte_intr_instance_free(afu_dev->intr_handle);
+ afu_dev->intr_handle = NULL;
+ }
- return afu_drv->probe(afu_dev);
+ return ret;
}
/*
--
2.54.0
^ permalink raw reply related
* [PATCH v4 07/12] bus/vmbus: allocate interrupt during probing
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Wei Hu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
Allocating the interrupt handle is a waste of memory if no device is
probed later (like for example, if a allowlist is passed).
Instead, allocate this handle at the time probe_device is called.
Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
Changes since v1:
- fixed/reordered interrupt handle allocation,
---
drivers/bus/vmbus/linux/vmbus_bus.c | 6 ------
drivers/bus/vmbus/vmbus_common.c | 18 ++++++++++++++++--
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/bus/vmbus/linux/vmbus_bus.c b/drivers/bus/vmbus/linux/vmbus_bus.c
index 0af10f6a69..77d904ad6d 100644
--- a/drivers/bus/vmbus/linux/vmbus_bus.c
+++ b/drivers/bus/vmbus/linux/vmbus_bus.c
@@ -345,12 +345,6 @@ vmbus_scan_one(const char *name)
}
}
- /* Allocate interrupt handle instance */
- dev->intr_handle =
- rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
- if (dev->intr_handle == NULL)
- goto error;
-
/* device is valid, add in list (sorted) */
VMBUS_LOG(DEBUG, "Adding vmbus device %s", name);
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 74c1ddff69..bfb45e963c 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -100,10 +100,16 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
return 1;
}
+ /* allocate interrupt handle instance */
+ vmbus_dev->intr_handle =
+ rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
+ if (vmbus_dev->intr_handle == NULL)
+ return -ENOMEM;
+
/* map resources for device */
ret = rte_vmbus_map_device(vmbus_dev);
if (ret != 0)
- return ret;
+ goto free_intr;
if (vmbus_dev->device.numa_node < 0 && rte_socket_count() > 1)
VMBUS_LOG(INFO, "Device %s is not NUMA-aware", guid);
@@ -112,7 +118,15 @@ vmbus_probe_device(struct rte_driver *drv, struct rte_device *dev)
VMBUS_LOG(INFO, " probe driver: %s", vmbus_drv->driver.name);
ret = vmbus_drv->probe(vmbus_drv, vmbus_dev);
if (ret != 0)
- rte_vmbus_unmap_device(vmbus_dev);
+ goto unmap;
+
+ return 0;
+
+unmap:
+ rte_vmbus_unmap_device(vmbus_dev);
+free_intr:
+ rte_intr_instance_free(vmbus_dev->intr_handle);
+ vmbus_dev->intr_handle = NULL;
return ret;
}
--
2.54.0
^ permalink raw reply related
* [PATCH v4 06/12] bus/vmbus: fix interrupt leak in cleanup
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Wei Hu
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
When calling this bus cleanup, interrupt handle was not released.
Fixes: 65780eada9d9 ("bus/vmbus: support cleanup")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
Reviewed-by: Long Li <longli@microsoft.com>
---
drivers/bus/vmbus/vmbus_common.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bus/vmbus/vmbus_common.c b/drivers/bus/vmbus/vmbus_common.c
index 01573927ce..74c1ddff69 100644
--- a/drivers/bus/vmbus/vmbus_common.c
+++ b/drivers/bus/vmbus/vmbus_common.c
@@ -150,6 +150,7 @@ rte_vmbus_cleanup(void)
error = -1;
rte_vmbus_unmap_device(dev);
+ rte_intr_instance_free(dev->intr_handle);
dev->device.driver = NULL;
rte_bus_remove_device(&rte_vmbus_bus, &dev->device);
--
2.54.0
^ permalink raw reply related
* [PATCH v4 05/12] bus/pci: fix mapping leak in bus cleanup
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Chenbo Xia, Nipun Gupta,
Morten Brørup, Kevin Laatz
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
When calling this bus cleanup, PCI resources were not unmapped.
Fixes: 1cab1a40ea9b ("bus: cleanup devices on shutdown")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/bus/pci/pci_common.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index fd18b8772b..791e9a7b49 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -344,6 +344,10 @@ pci_cleanup(void)
rte_errno = errno;
error = -1;
}
+
+ if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
+ rte_pci_unmap_device(dev);
+
dev->device.driver = NULL;
free:
--
2.54.0
^ permalink raw reply related
* [PATCH v4 04/12] vdpa/nfp: fix double PCI unmap on unplug
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, stable, Chaoyong He, Peng Zhang, Long Wu,
Shujing Dong
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
This driver uses its own VFIO container and handles mapping/unmapping
itself. It should not use RTE_PCI_DRV_NEED_MAPPING flag, which causes
the PCI bus to also attempt unmapping, resulting in double free.
Fixes: 7b2a1228c59d ("vdpa/nfp: add remap PCI memory")
Cc: stable@dpdk.org
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
drivers/vdpa/nfp/nfp_vdpa.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/vdpa/nfp/nfp_vdpa.c b/drivers/vdpa/nfp/nfp_vdpa.c
index f4fd5c92ec..4c0ab3ff30 100644
--- a/drivers/vdpa/nfp/nfp_vdpa.c
+++ b/drivers/vdpa/nfp/nfp_vdpa.c
@@ -119,8 +119,6 @@ nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)
char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
struct rte_pci_device *pci_dev = device->pci_dev;
- rte_pci_unmap_device(pci_dev);
-
rte_pci_device_name(&pci_dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
&device->iommu_group);
@@ -1301,7 +1299,7 @@ static struct nfp_class_driver nfp_vdpa = {
.drv_class = NFP_CLASS_VDPA,
.name = RTE_STR(NFP_VDPA_DRIVER_NAME),
.id_table = pci_id_nfp_vdpa_map,
- .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
+ .drv_flags = RTE_PCI_DRV_INTR_LSC,
.probe = nfp_vdpa_pci_probe,
.remove = nfp_vdpa_pci_remove,
};
--
2.54.0
^ permalink raw reply related
* [PATCH v4 03/12] bus/vdev: remove driver setting in probe
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
Setting the device driver field is not the responsibility of the
probe_device callback anymore, but that of EAL (see local_dev_probe).
Yet, because of the VDEV API, rte_vdev_init() must be updated to mark
the device as probed.
Fixes: f282771a04ef ("bus: factorize driver reference")
Signed-off-by: David Marchand <david.marchand@redhat.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
Changes since v1:
- implement the same way as EAL,
---
drivers/bus/vdev/vdev.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 3bddf8938c..09221ccdea 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -188,7 +188,6 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
struct rte_vdev_driver *vdev_drv = RTE_BUS_DRIVER(drv, *vdev_drv);
const char *name;
enum rte_iova_mode iova_mode;
- int ret;
name = rte_vdev_device_name(vdev_dev);
VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
@@ -200,10 +199,7 @@ vdev_probe_device(struct rte_driver *drv, struct rte_device *dev)
return -1;
}
- ret = vdev_drv->probe(vdev_dev);
- if (ret == 0)
- vdev_dev->device.driver = &vdev_drv->driver;
- return ret;
+ return vdev_drv->probe(vdev_dev);
}
/* The caller shall be responsible for thread-safe */
@@ -328,7 +324,10 @@ rte_vdev_init(const char *name, const char *args)
} else if (rte_dev_is_probed(&dev->device)) {
ret = -EEXIST;
} else {
+ dev->device.driver = drv;
ret = rte_vdev_bus.probe_device(drv, &dev->device);
+ if (ret != 0)
+ dev->device.driver = NULL;
}
if (ret < 0) {
/* If fails, remove it from vdev list */
--
2.54.0
^ permalink raw reply related
* [PATCH v4 02/12] dma/idxd: remove next pointer in bus specific device
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev
Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal, Kevin Laatz
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
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>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/dma/idxd/idxd_bus.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/dma/idxd/idxd_bus.c b/drivers/dma/idxd/idxd_bus.c
index 4810d52f2a..2ec526ec09 100644
--- a/drivers/dma/idxd/idxd_bus.c
+++ b/drivers/dma/idxd/idxd_bus.c
@@ -34,7 +34,6 @@ struct dsa_wq_addr {
/** a DSA device instance */
struct rte_dsa_device {
struct rte_device device; /**< Inherit core device */
- TAILQ_ENTRY(rte_dsa_device) next; /**< next dev in list */
char wq_name[32]; /**< the workqueue name/number e.g. wq0.1 */
struct dsa_wq_addr addr; /**< Identifies the specific WQ */
--
2.54.0
^ permalink raw reply related
* [PATCH v4 01/12] bus: fix reference to plug callback
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
In-Reply-To: <20260624104324.3576408-1-david.marchand@redhat.com>
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>
Acked-by: Bruce Richardson <bruce.richardson@intel.com>
Acked-by: Chengwen Feng <fengchengwen@huawei.com>
---
Changes since v1:
- remove missed rte_bus_plug_t typedef,
---
doc/guides/prog_guide/device_hotplug.rst | 2 +-
lib/eal/common/eal_common_dev.c | 2 +-
lib/eal/include/bus_driver.h | 13 -------------
3 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/doc/guides/prog_guide/device_hotplug.rst b/doc/guides/prog_guide/device_hotplug.rst
index 9896a097f3..7eb7fbcc2b 100644
--- a/doc/guides/prog_guide/device_hotplug.rst
+++ b/doc/guides/prog_guide/device_hotplug.rst
@@ -234,7 +234,7 @@ When ``rte_dev_probe()`` is called, the following sequence occurs:
and the attach operation fails if the device is not found.
#. **Device Probe**:
- The bus's ``plug()`` method is called, which triggers the device driver's probe function.
+ The bus's ``probe_device()`` method is called, which triggers the device driver's probe function.
The probe function typically allocates device-specific resources,
maps device memory regions, initializes device hardware,
and registers the device with the appropriate subsystem (e.g., ethdev for network devices).
diff --git a/lib/eal/common/eal_common_dev.c b/lib/eal/common/eal_common_dev.c
index 48b631532a..2a2103ec57 100644
--- a/lib/eal/common/eal_common_dev.c
+++ b/lib/eal/common/eal_common_dev.c
@@ -193,7 +193,7 @@ local_dev_probe(const char *devargs, struct rte_device **new_dev)
goto err_devarg;
if (da->bus->probe_device == NULL) {
- EAL_LOG(ERR, "Function plug not supported by bus (%s)",
+ EAL_LOG(ERR, "Function probe_device not supported by bus (%s)",
da->bus->name);
ret = -ENOTSUP;
goto err_devarg;
diff --git a/lib/eal/include/bus_driver.h b/lib/eal/include/bus_driver.h
index 0a7e23d98d..9711e6712b 100644
--- a/lib/eal/include/bus_driver.h
+++ b/lib/eal/include/bus_driver.h
@@ -75,19 +75,6 @@ typedef struct rte_device *
(*rte_bus_find_device_t)(const struct rte_bus *bus, const struct rte_device *start,
rte_dev_cmp_t cmp, const void *data);
-/**
- * Implementation specific probe function which is responsible for linking
- * devices on that bus with applicable drivers.
- *
- * @param dev
- * Device pointer that was returned by a previous call to find_device.
- *
- * @return
- * 0 on success.
- * !0 on error.
- */
-typedef int (*rte_bus_plug_t)(struct rte_device *dev);
-
/**
* Implementation specific probe function which is responsible for linking
* devices on that bus with applicable drivers.
--
2.54.0
^ permalink raw reply related
* [PATCH v4 00/12] Bus cleanup infrastructure and fixes
From: David Marchand @ 2026-06-24 10:43 UTC (permalink / raw)
To: dev; +Cc: thomas, stephen, bruce.richardson, fengchengwen, longli,
hemant.agrawal
In-Reply-To: <20260611094551.1514962-1-david.marchand@redhat.com>
This is a followup of the previous bus refactoring.
See https://inbox.dpdk.org/dev/CAJFAV8zvFpLwz8SY8DUUezyJyM43eRZ17Yj30ex808eHC4ZE=g@mail.gmail.com/.
This series refactors the bus cleanup infrastructure to reduce code
duplication and fix resource leaks in several bus drivers.
It should address the leak Thomas pointed at.
The first part of the series (patches 1-6) addresses several bugs and
inconsistencies:
- Documentation and log message inconsistencies from earlier bus
refactoring
- Device list management issues in dma/idxd and bus/vdev
- Resource leaks in PCI and VMBUS bus cleanup (mappings and interrupts)
- Deferred interrupt allocation to probe time (VMBUS)
The core infrastructure changes (patches 7-8) introduce the generic
cleanup framework:
- Refactors unplug operations to be the counterpart of probe_device
- Implements rte_bus_generic_cleanup() to centralize cleanup logic
- Adds .free_device operation to struct rte_bus
The final patches (9-10) convert the VMBUS bus to use the generic
cleanup helper.
After this series, most buses use the generic cleanup helper, eliminating
duplicated code and ensuring consistent cleanup behavior across the
codebase.
NXP bus drivers require more (leak) fixes and refactoring and
are left untouched.
--
David Marchand
Changes since v3:
- added fix on vdpa/nfp,
Changes since v2:
- moved ifpga interruption allocation,
Changes since v1:
- dropped all changes on DPAA and FSLMC bus,
- added one more cleanup on the first patch,
- changed coding style in rte_vdev_init,
- implemented explicit .free_device instead of hack for calling free(),
- reordered interrupt handle allocation in VMBUS bus,
David Marchand (12):
bus: fix reference to plug callback
dma/idxd: remove next pointer in bus specific device
bus/vdev: remove driver setting in probe
vdpa/nfp: fix double PCI unmap on unplug
bus/pci: fix mapping leak in bus cleanup
bus/vmbus: fix interrupt leak in cleanup
bus/vmbus: allocate interrupt during probing
bus/ifpga: allocate interrupt during probing
bus: align unplug with device probe
bus: implement cleanup in EAL
bus/vmbus: store name in bus specific device
bus/vmbus: support unplug
doc/guides/prog_guide/device_hotplug.rst | 20 +++---
doc/guides/rel_notes/release_26_07.rst | 4 ++
drivers/bus/auxiliary/auxiliary_common.c | 54 +++------------
drivers/bus/cdx/cdx.c | 29 ++------
drivers/bus/dpaa/dpaa_bus.c | 4 +-
drivers/bus/fslmc/fslmc_bus.c | 9 +--
drivers/bus/ifpga/ifpga_bus.c | 88 ++++++++----------------
drivers/bus/pci/pci_common.c | 68 +++---------------
drivers/bus/platform/platform.c | 26 ++-----
drivers/bus/uacce/uacce.c | 59 +++-------------
drivers/bus/vdev/vdev.c | 76 ++++++++------------
drivers/bus/vmbus/bus_vmbus_driver.h | 1 +
drivers/bus/vmbus/linux/vmbus_bus.c | 16 +----
drivers/bus/vmbus/vmbus_common.c | 58 +++++++++-------
drivers/dma/idxd/idxd_bus.c | 1 -
drivers/vdpa/nfp/nfp_vdpa.c | 4 +-
lib/eal/common/eal_common_bus.c | 33 ++++++++-
lib/eal/common/eal_common_dev.c | 10 +--
lib/eal/include/bus_driver.h | 51 +++++++++-----
19 files changed, 235 insertions(+), 376 deletions(-)
--
2.54.0
^ permalink raw reply
* [PATCH v2 17/17] net/virtio: replace strncpy with strlcpy
From: Bruce Richardson @ 2026-06-24 10:36 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, stable, Maxime Coquelin, Chenbo Xia,
David Marchand
In-Reply-To: <20260624103658.792750-1-bruce.richardson@intel.com>
Replace strncpy() with safer strlcpy() which always null-terminates.
Fixes: b72099be7f27 ("net/virtio-user: fix init when using existing tap")
Cc: stable@dpdk.org
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/net/virtio/virtio_user/vhost_kernel_tap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/virtio/virtio_user/vhost_kernel_tap.c b/drivers/net/virtio/virtio_user/vhost_kernel_tap.c
index 2431d00c33..da55aba505 100644
--- a/drivers/net/virtio/virtio_user/vhost_kernel_tap.c
+++ b/drivers/net/virtio/virtio_user/vhost_kernel_tap.c
@@ -60,7 +60,7 @@ vhost_tap_open(const char *ifname, unsigned int r_flags, bool multi_queue)
retry_mono_q:
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
+ strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = r_flags;
if (multi_queue)
ifr.ifr_flags |= IFF_MULTI_QUEUE;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 16/17] net/vhost: replace strncpy with strlcpy
From: Bruce Richardson @ 2026-06-24 10:36 UTC (permalink / raw)
To: dev; +Cc: Bruce Richardson, stable, Maxime Coquelin, Chenbo Xia
In-Reply-To: <20260624103658.792750-1-bruce.richardson@intel.com>
Replace strncpy() with safer strlcpy() which always null-terminates.
Fixes: 2e16597c4bda ("net/vhost: move to vhost library statistics API")
Cc: stable@dpdk.org
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
drivers/net/vhost/rte_eth_vhost.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/vhost/rte_eth_vhost.c b/drivers/net/vhost/rte_eth_vhost.c
index 05940f2461..82e9fc929a 100644
--- a/drivers/net/vhost/rte_eth_vhost.c
+++ b/drivers/net/vhost/rte_eth_vhost.c
@@ -209,7 +209,7 @@ vhost_dev_xstats_get_names(struct rte_eth_dev *dev,
}
for (i = 0; i < count; i++)
- strncpy(xstats_names[i].name, name[i].name, RTE_ETH_XSTATS_NAME_SIZE);
+ strlcpy(xstats_names[i].name, name[i].name, RTE_ETH_XSTATS_NAME_SIZE);
free(name);
--
2.53.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