* [PATCH iwl-net 0/2] idpf: Fix vport state handling
@ 2025-08-22 3:52 Emil Tantilov
2025-08-22 3:52 ` [PATCH iwl-net 1/2] idpf: convert vport state to bitmap Emil Tantilov
2025-08-22 3:52 ` [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop() Emil Tantilov
0 siblings, 2 replies; 5+ messages in thread
From: Emil Tantilov @ 2025-08-22 3:52 UTC (permalink / raw)
To: intel-wired-lan
Cc: netdev, Aleksandr.Loktionov, przemyslaw.kitszel, anthony.l.nguyen,
andrew+netdev, davem, edumazet, kuba, pabeni, decot, willemb,
joshua.a.hay, madhu.chittim
While testing the support for setting the MAC type [0], rmmod while
multiple vports are up would occasionally report an error, caused by a
VC message being sent with opcode 536, attempting to delete a MAC filter
that was already deleted by the call to idpf_vport_stop():
idpf 0000:83:00.0: Received invalid MAC filter payload (op 536) (len 0)
This can happen as idpf_addr_unsync() is called via ndo_set_rx_mode()
while idpf_vport_stop() is called by rmmod:
rmmod-231066 [004] ..... 100851.014226: idpf_add_del_mac_filters <-idpf_vport_stop
systemd-resolve-1364 [029] b..1. 100851.159457: idpf_add_del_mac_filters <-idpf_addr_unsync
Though the issue was discovered while testing the MAC type change, it is
not specific to that flow, hence why it is posted in a separate series.
While it can be applied on its own, for the purpose of testing it is
recommended to be applied on top of [0].
The changes are split in 2 parts:
- The first commit is just a conversion to bitmap for the vport state.
- Second commit plugs the race by making sure the IDPF_VPORT_UP bit is
cleared by idpf_vport_stop() on entry.
[0] https://lore.kernel.org/intel-wired-lan/20250814234300.2926-1-emil.s.tantilov@intel.com/
Emil Tantilov (2):
idpf: convert vport state to bitmap
idpf: fix possible race in idpf_vport_stop()
drivers/net/ethernet/intel/idpf/idpf.h | 12 ++++------
.../net/ethernet/intel/idpf/idpf_ethtool.c | 10 ++++----
drivers/net/ethernet/intel/idpf/idpf_lib.c | 23 +++++++++----------
.../ethernet/intel/idpf/idpf_singleq_txrx.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
.../net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++--
6 files changed, 25 insertions(+), 28 deletions(-)
--
2.37.3
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH iwl-net 1/2] idpf: convert vport state to bitmap
2025-08-22 3:52 [PATCH iwl-net 0/2] idpf: Fix vport state handling Emil Tantilov
@ 2025-08-22 3:52 ` Emil Tantilov
2025-08-27 14:19 ` Simon Horman
2025-08-22 3:52 ` [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop() Emil Tantilov
1 sibling, 1 reply; 5+ messages in thread
From: Emil Tantilov @ 2025-08-22 3:52 UTC (permalink / raw)
To: intel-wired-lan
Cc: netdev, Aleksandr.Loktionov, przemyslaw.kitszel, anthony.l.nguyen,
andrew+netdev, davem, edumazet, kuba, pabeni, decot, willemb,
joshua.a.hay, madhu.chittim
Convert vport state to a bitmap and remove the DOWN state which is
redundant in the existing logic. There are no functional changes aside
from the use of bitwise operations when setting and checking the states.
Removed the double underscore to be consistent with the naming of other
bitmaps in the header and renamed current_state to vport_is_up to match
the meaning of the new variable.
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Chittim Madhu <madhu.chittim@intel.com>
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
---
drivers/net/ethernet/intel/idpf/idpf.h | 12 ++++------
.../net/ethernet/intel/idpf/idpf_ethtool.c | 10 ++++----
drivers/net/ethernet/intel/idpf/idpf_lib.c | 24 +++++++++----------
.../ethernet/intel/idpf/idpf_singleq_txrx.c | 2 +-
drivers/net/ethernet/intel/idpf/idpf_txrx.c | 2 +-
.../net/ethernet/intel/idpf/idpf_virtchnl.c | 4 ++--
6 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index f4c0eaf9bde3..cfbf3a716f34 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -130,14 +130,12 @@ enum idpf_cap_field {
/**
* enum idpf_vport_state - Current vport state
- * @__IDPF_VPORT_DOWN: Vport is down
- * @__IDPF_VPORT_UP: Vport is up
- * @__IDPF_VPORT_STATE_LAST: Must be last, number of states
+ * @IDPF_VPORT_UP: Vport is up
+ * @IDPF_VPORT_STATE_NBITS: Must be last, number of states
*/
enum idpf_vport_state {
- __IDPF_VPORT_DOWN,
- __IDPF_VPORT_UP,
- __IDPF_VPORT_STATE_LAST,
+ IDPF_VPORT_UP,
+ IDPF_VPORT_STATE_NBITS
};
/**
@@ -159,7 +157,7 @@ struct idpf_netdev_priv {
u32 link_speed_mbps;
u16 vport_idx;
u16 max_tx_hdr_size;
- enum idpf_vport_state state;
+ DECLARE_BITMAP(state, IDPF_VPORT_STATE_NBITS);
struct rtnl_link_stats64 netstats;
spinlock_t stats_lock;
};
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 0eb812ac19c2..f84e247399a7 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -386,7 +386,7 @@ static int idpf_get_rxfh(struct net_device *netdev,
}
rss_data = &adapter->vport_config[np->vport_idx]->user_config.rss_data;
- if (np->state != __IDPF_VPORT_UP)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
rxfh->hfunc = ETH_RSS_HASH_TOP;
@@ -436,7 +436,7 @@ static int idpf_set_rxfh(struct net_device *netdev,
}
rss_data = &adapter->vport_config[vport->idx]->user_config.rss_data;
- if (np->state != __IDPF_VPORT_UP)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
@@ -1167,7 +1167,7 @@ static void idpf_get_ethtool_stats(struct net_device *netdev,
idpf_vport_ctrl_lock(netdev);
vport = idpf_netdev_to_vport(netdev);
- if (np->state != __IDPF_VPORT_UP) {
+ if (!test_bit(IDPF_VPORT_UP, np->state)) {
idpf_vport_ctrl_unlock(netdev);
return;
@@ -1319,7 +1319,7 @@ static int idpf_get_q_coalesce(struct net_device *netdev,
idpf_vport_ctrl_lock(netdev);
vport = idpf_netdev_to_vport(netdev);
- if (np->state != __IDPF_VPORT_UP)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
if (q_num >= vport->num_rxq && q_num >= vport->num_txq) {
@@ -1507,7 +1507,7 @@ static int idpf_set_coalesce(struct net_device *netdev,
idpf_vport_ctrl_lock(netdev);
vport = idpf_netdev_to_vport(netdev);
- if (np->state != __IDPF_VPORT_UP)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
goto unlock_mutex;
for (i = 0; i < vport->num_txq; i++) {
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 513032cb5f08..89d30c395533 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -517,7 +517,7 @@ static int idpf_del_mac_filter(struct idpf_vport *vport,
}
spin_unlock_bh(&vport_config->mac_filter_list_lock);
- if (np->state == __IDPF_VPORT_UP) {
+ if (test_bit(IDPF_VPORT_UP, np->state)) {
int err;
err = idpf_add_del_mac_filters(vport, np, false, async);
@@ -588,7 +588,7 @@ static int idpf_add_mac_filter(struct idpf_vport *vport,
if (err)
return err;
- if (np->state == __IDPF_VPORT_UP)
+ if (test_bit(IDPF_VPORT_UP, np->state))
err = idpf_add_del_mac_filters(vport, np, true, async);
return err;
@@ -888,7 +888,7 @@ static void idpf_vport_stop(struct idpf_vport *vport)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
- if (np->state <= __IDPF_VPORT_DOWN)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
return;
netif_carrier_off(vport->netdev);
@@ -911,7 +911,7 @@ static void idpf_vport_stop(struct idpf_vport *vport)
idpf_vport_intr_deinit(vport);
idpf_vport_queues_rel(vport);
idpf_vport_intr_rel(vport);
- np->state = __IDPF_VPORT_DOWN;
+ clear_bit(IDPF_VPORT_UP, np->state);
}
/**
@@ -1332,7 +1332,7 @@ static int idpf_up_complete(struct idpf_vport *vport)
netif_tx_start_all_queues(vport->netdev);
}
- np->state = __IDPF_VPORT_UP;
+ set_bit(IDPF_VPORT_UP, np->state);
return 0;
}
@@ -1377,7 +1377,7 @@ static int idpf_vport_open(struct idpf_vport *vport)
struct idpf_vport_config *vport_config;
int err;
- if (np->state != __IDPF_VPORT_DOWN)
+ if (test_bit(IDPF_VPORT_UP, np->state))
return -EBUSY;
/* we do not allow interface up just yet */
@@ -1569,7 +1569,7 @@ void idpf_init_task(struct work_struct *work)
/* Once state is put into DOWN, driver is ready for dev_open */
np = netdev_priv(vport->netdev);
- np->state = __IDPF_VPORT_DOWN;
+ clear_bit(IDPF_VPORT_UP, np->state);
if (test_and_clear_bit(IDPF_VPORT_UP_REQUESTED, vport_config->flags))
idpf_vport_open(vport);
@@ -1768,7 +1768,7 @@ static void idpf_set_vport_state(struct idpf_adapter *adapter)
continue;
np = netdev_priv(adapter->netdevs[i]);
- if (np->state == __IDPF_VPORT_UP)
+ if (test_bit(IDPF_VPORT_UP, np->state))
set_bit(IDPF_VPORT_UP_REQUESTED,
adapter->vport_config[i]->flags);
}
@@ -1906,7 +1906,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
enum idpf_vport_reset_cause reset_cause)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
- enum idpf_vport_state current_state = np->state;
+ bool vport_is_up = test_bit(IDPF_VPORT_UP, np->state);
struct idpf_adapter *adapter = vport->adapter;
struct idpf_vport *new_vport;
int err;
@@ -1957,7 +1957,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
goto free_vport;
}
- if (current_state <= __IDPF_VPORT_DOWN) {
+ if (!vport_is_up) {
idpf_send_delete_queues_msg(vport);
} else {
set_bit(IDPF_VPORT_DEL_QUEUES, vport->flags);
@@ -1990,7 +1990,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
if (err)
goto err_open;
- if (current_state == __IDPF_VPORT_UP)
+ if (vport_is_up)
err = idpf_vport_open(vport);
goto free_vport;
@@ -2000,7 +2000,7 @@ int idpf_initiate_soft_reset(struct idpf_vport *vport,
vport->num_rxq, vport->num_bufq);
err_open:
- if (current_state == __IDPF_VPORT_UP)
+ if (vport_is_up)
idpf_vport_open(vport);
free_vport:
diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
index b19b462e0bb6..06199fde3b57 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -571,7 +571,7 @@ static bool idpf_tx_singleq_clean(struct idpf_tx_queue *tx_q, int napi_budget,
np = netdev_priv(tx_q->netdev);
nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx);
- dont_wake = np->state != __IDPF_VPORT_UP ||
+ dont_wake = !test_bit(IDPF_VPORT_UP, np->state) ||
!netif_carrier_ok(tx_q->netdev);
__netif_txq_completed_wake(nq, ss.packets, ss.bytes,
IDPF_DESC_UNUSED(tx_q), IDPF_TX_WAKE_THRESH,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 68b3857c803b..b72d3e4d40f7 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1868,7 +1868,7 @@ static bool idpf_tx_clean_complq(struct idpf_compl_queue *complq, int budget,
/* Update BQL */
nq = netdev_get_tx_queue(tx_q->netdev, tx_q->idx);
- dont_wake = !complq_ok || np->state != __IDPF_VPORT_UP ||
+ dont_wake = !complq_ok || !test_bit(IDPF_VPORT_UP, np->state) ||
!netif_carrier_ok(tx_q->netdev);
/* Check if the TXQ needs to and can be restarted */
__netif_txq_completed_wake(nq, tx_q->cleaned_pkts, tx_q->cleaned_bytes,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 6330d4a0ae07..d751d40c4e46 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -68,7 +68,7 @@ static void idpf_handle_event_link(struct idpf_adapter *adapter,
vport->link_up = v2e->link_status;
- if (np->state != __IDPF_VPORT_UP)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
return;
if (vport->link_up) {
@@ -2432,7 +2432,7 @@ int idpf_send_get_stats_msg(struct idpf_vport *vport)
/* Don't send get_stats message if the link is down */
- if (np->state <= __IDPF_VPORT_DOWN)
+ if (!test_bit(IDPF_VPORT_UP, np->state))
return 0;
stats_msg.vport_id = cpu_to_le32(vport->vport_id);
--
2.37.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop()
2025-08-22 3:52 [PATCH iwl-net 0/2] idpf: Fix vport state handling Emil Tantilov
2025-08-22 3:52 ` [PATCH iwl-net 1/2] idpf: convert vport state to bitmap Emil Tantilov
@ 2025-08-22 3:52 ` Emil Tantilov
2025-08-27 14:20 ` Simon Horman
1 sibling, 1 reply; 5+ messages in thread
From: Emil Tantilov @ 2025-08-22 3:52 UTC (permalink / raw)
To: intel-wired-lan
Cc: netdev, Aleksandr.Loktionov, przemyslaw.kitszel, anthony.l.nguyen,
andrew+netdev, davem, edumazet, kuba, pabeni, decot, willemb,
joshua.a.hay, madhu.chittim
Make sure to clear the IDPF_VPORT_UP bit on entry. The idpf_vport_stop()
function is void and once called, the vport teardown is guaranteed to
happen. Previously the bit was cleared at the end of the function, which
opened it up to possible races with all instances in the driver where
operations were conditional on this bit being set. For example, on rmmod
callbacks in the middle of idpf_vport_stop() end up attempting to remove
MAC address filter already removed by the function:
idpf 0000:83:00.0: Received invalid MAC filter payload (op 536) (len 0)
Fixes: 1c325aac10a8 ("idpf: configure resources for TX queues")
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by Joshua Hay <joshua.a.hay@intel.com>
Reviewed-by: Chittim Madhu <madhu.chittim@intel.com>
Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
---
drivers/net/ethernet/intel/idpf/idpf_lib.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 89d30c395533..01ab42fa23f9 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -888,7 +888,7 @@ static void idpf_vport_stop(struct idpf_vport *vport)
{
struct idpf_netdev_priv *np = netdev_priv(vport->netdev);
- if (!test_bit(IDPF_VPORT_UP, np->state))
+ if (!test_and_clear_bit(IDPF_VPORT_UP, np->state))
return;
netif_carrier_off(vport->netdev);
@@ -911,7 +911,6 @@ static void idpf_vport_stop(struct idpf_vport *vport)
idpf_vport_intr_deinit(vport);
idpf_vport_queues_rel(vport);
idpf_vport_intr_rel(vport);
- clear_bit(IDPF_VPORT_UP, np->state);
}
/**
--
2.37.3
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH iwl-net 1/2] idpf: convert vport state to bitmap
2025-08-22 3:52 ` [PATCH iwl-net 1/2] idpf: convert vport state to bitmap Emil Tantilov
@ 2025-08-27 14:19 ` Simon Horman
0 siblings, 0 replies; 5+ messages in thread
From: Simon Horman @ 2025-08-27 14:19 UTC (permalink / raw)
To: Emil Tantilov
Cc: intel-wired-lan, netdev, Aleksandr.Loktionov, przemyslaw.kitszel,
anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni,
decot, willemb, joshua.a.hay, madhu.chittim
On Thu, Aug 21, 2025 at 08:52:47PM -0700, Emil Tantilov wrote:
> Convert vport state to a bitmap and remove the DOWN state which is
> redundant in the existing logic. There are no functional changes aside
> from the use of bitwise operations when setting and checking the states.
> Removed the double underscore to be consistent with the naming of other
> bitmaps in the header and renamed current_state to vport_is_up to match
> the meaning of the new variable.
>
> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Reviewed-by: Chittim Madhu <madhu.chittim@intel.com>
> Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop()
2025-08-22 3:52 ` [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop() Emil Tantilov
@ 2025-08-27 14:20 ` Simon Horman
0 siblings, 0 replies; 5+ messages in thread
From: Simon Horman @ 2025-08-27 14:20 UTC (permalink / raw)
To: Emil Tantilov
Cc: intel-wired-lan, netdev, Aleksandr.Loktionov, przemyslaw.kitszel,
anthony.l.nguyen, andrew+netdev, davem, edumazet, kuba, pabeni,
decot, willemb, joshua.a.hay, madhu.chittim
On Thu, Aug 21, 2025 at 08:52:48PM -0700, Emil Tantilov wrote:
> Make sure to clear the IDPF_VPORT_UP bit on entry. The idpf_vport_stop()
> function is void and once called, the vport teardown is guaranteed to
> happen. Previously the bit was cleared at the end of the function, which
> opened it up to possible races with all instances in the driver where
> operations were conditional on this bit being set. For example, on rmmod
> callbacks in the middle of idpf_vport_stop() end up attempting to remove
> MAC address filter already removed by the function:
> idpf 0000:83:00.0: Received invalid MAC filter payload (op 536) (len 0)
>
> Fixes: 1c325aac10a8 ("idpf: configure resources for TX queues")
> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
> Reviewed-by Joshua Hay <joshua.a.hay@intel.com>
> Reviewed-by: Chittim Madhu <madhu.chittim@intel.com>
> Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-08-27 14:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-22 3:52 [PATCH iwl-net 0/2] idpf: Fix vport state handling Emil Tantilov
2025-08-22 3:52 ` [PATCH iwl-net 1/2] idpf: convert vport state to bitmap Emil Tantilov
2025-08-27 14:19 ` Simon Horman
2025-08-22 3:52 ` [PATCH iwl-net 2/2] idpf: fix possible race in idpf_vport_stop() Emil Tantilov
2025-08-27 14:20 ` Simon Horman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).