From: Xuanqiang Luo <[email protected]>
i40e_remove() can call i40e_ptp_stop() without the networking locks held.
A concurrent hardware timestamp request can observe I40E_FLAG_PTP_ENA
before teardown clears it, then program PRTTSYN_CTL0 after teardown has
disabled the event source. This can leave time sync interrupts enabled
during device removal.
Add ptp_config_lock to serialize the enable check and register programming
in i40e_ptp_hwtstamp_set() with the PTP state transition in
i40e_ptp_stop(). Requests which observe PTP enabled finish programming
before the state transition; later requests return -EOPNOTSUPP and cannot
re-enable the interrupt.
Fixes: 1050713026a0 ("i40e: add support for PTP external synchronization clock")
Signed-off-by: Xuanqiang Luo <[email protected]>
---
drivers/net/ethernet/intel/i40e/i40e.h | 2 ++
drivers/net/ethernet/intel/i40e/i40e_main.c | 1 +
drivers/net/ethernet/intel/i40e/i40e_ptp.c | 17 +++++++++++++----
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 4c8bcaa9dd192..84564d747d09a 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -668,6 +668,8 @@ struct i40e_pf {
struct timespec64 ptp_prev_hw_time;
struct work_struct ptp_extts0_work;
ktime_t ptp_reset_start;
+ /* Serializes timestamp configuration with PTP teardown. */
+ struct mutex ptp_config_lock;
struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */
u32 ptp_adj_mult;
u32 tx_hwtstamp_timeouts;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 0a259351c127e..8c28788ac634f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -12819,6 +12819,7 @@ static int i40e_sw_init(struct i40e_pf *pf)
"total-port-shutdown was enabled, link-down-on-close is forced on\n");
}
mutex_init(&pf->switch_mutex);
+ mutex_init(&pf->ptp_config_lock);
spin_lock_init(&pf->ptp_tx_lock);
sw_init_done:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 224568a3af085..f194869947124 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -1328,17 +1328,23 @@ int i40e_ptp_hwtstamp_set(struct net_device *netdev,
struct i40e_pf *pf = np->vsi->back;
int err;
- if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
- return -EOPNOTSUPP;
+ mutex_lock(&pf->ptp_config_lock);
+
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags)) {
+ err = -EOPNOTSUPP;
+ goto unlock;
+ }
err = i40e_ptp_set_timestamp_mode(pf, config);
if (err)
- return err;
+ goto unlock;
/* save these settings for future reference */
pf->tstamp_config = *config;
- return 0;
+unlock:
+ mutex_unlock(&pf->ptp_config_lock);
+ return err;
}
/**
@@ -1558,6 +1564,8 @@ void i40e_ptp_stop(struct i40e_pf *pf)
struct sk_buff *skb;
u32 regval;
+ mutex_lock(&pf->ptp_config_lock);
+
spin_lock_irqsave(&pf->ptp_tx_lock, flags);
clear_bit(I40E_FLAG_PTP_ENA, pf->flags);
pf->ptp_tx = false;
@@ -1566,6 +1574,7 @@ void i40e_ptp_stop(struct i40e_pf *pf)
spin_unlock_irqrestore(&pf->ptp_tx_lock, flags);
pf->ptp_rx = false;
+ mutex_unlock(&pf->ptp_config_lock);
if (skb)
dev_kfree_skb_any(skb);
--
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.