summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/intel/ice/ice_ptp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_ptp.c')
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c179
1 files changed, 109 insertions, 70 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 4c8d20f2d2c0..272683001476 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -573,6 +573,9 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
pf = ptp_port_to_pf(ptp_port);
hw = &pf->hw;
+ if (!tx->init)
+ return;
+
/* Read the Tx ready status first */
if (tx->has_ready_bitmap) {
err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready);
@@ -674,14 +677,9 @@ skip_ts_read:
pf->ptp.tx_hwtstamp_good += tstamp_good;
}
-/**
- * ice_ptp_tx_tstamp_owner - Process Tx timestamps for all ports on the device
- * @pf: Board private structure
- */
-static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
+static void ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
{
struct ice_ptp_port *port;
- unsigned int i;
mutex_lock(&pf->adapter->ports.lock);
list_for_each_entry(port, &pf->adapter->ports.ports, list_node) {
@@ -693,49 +691,6 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
ice_ptp_process_tx_tstamp(tx);
}
mutex_unlock(&pf->adapter->ports.lock);
-
- for (i = 0; i < ICE_GET_QUAD_NUM(pf->hw.ptp.num_lports); i++) {
- u64 tstamp_ready;
- int err;
-
- /* Read the Tx ready status first */
- err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (err)
- break;
- else if (tstamp_ready)
- return ICE_TX_TSTAMP_WORK_PENDING;
- }
-
- return ICE_TX_TSTAMP_WORK_DONE;
-}
-
-/**
- * ice_ptp_tx_tstamp - Process Tx timestamps for this function.
- * @tx: Tx tracking structure to initialize
- *
- * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding incomplete
- * Tx timestamps, or ICE_TX_TSTAMP_WORK_DONE otherwise.
- */
-static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
-{
- bool more_timestamps;
- unsigned long flags;
-
- if (!tx->init)
- return ICE_TX_TSTAMP_WORK_DONE;
-
- /* Process the Tx timestamp tracker */
- ice_ptp_process_tx_tstamp(tx);
-
- /* Check if there are outstanding Tx timestamps */
- spin_lock_irqsave(&tx->lock, flags);
- more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len);
- spin_unlock_irqrestore(&tx->lock, flags);
-
- if (more_timestamps)
- return ICE_TX_TSTAMP_WORK_PENDING;
-
- return ICE_TX_TSTAMP_WORK_DONE;
}
/**
@@ -1347,9 +1302,12 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup)
/* Do not reconfigure E810 or E830 PHY */
return;
case ICE_MAC_GENERIC:
- case ICE_MAC_GENERIC_3K_E825:
ice_ptp_port_phy_restart(ptp_port);
return;
+ case ICE_MAC_GENERIC_3K_E825:
+ if (linkup)
+ ice_ptp_port_phy_restart(ptp_port);
+ return;
default:
dev_warn(ice_pf_to_dev(pf), "%s: Unknown PHY type\n", __func__);
}
@@ -2663,30 +2621,92 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
return idx + tx->offset;
}
-/**
- * ice_ptp_process_ts - Process the PTP Tx timestamps
- * @pf: Board private structure
- *
- * Returns: ICE_TX_TSTAMP_WORK_PENDING if there are any outstanding Tx
- * timestamps that need processing, and ICE_TX_TSTAMP_WORK_DONE otherwise.
- */
-enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf)
+void ice_ptp_process_ts(struct ice_pf *pf)
{
switch (pf->ptp.tx_interrupt_mode) {
case ICE_PTP_TX_INTERRUPT_NONE:
/* This device has the clock owner handle timestamps for it */
- return ICE_TX_TSTAMP_WORK_DONE;
+ return;
case ICE_PTP_TX_INTERRUPT_SELF:
/* This device handles its own timestamps */
- return ice_ptp_tx_tstamp(&pf->ptp.port.tx);
+ ice_ptp_process_tx_tstamp(&pf->ptp.port.tx);
+ return;
case ICE_PTP_TX_INTERRUPT_ALL:
/* This device handles timestamps for all ports */
- return ice_ptp_tx_tstamp_owner(pf);
+ ice_ptp_tx_tstamp_owner(pf);
+ return;
+ default:
+ WARN_ONCE(1, "Unexpected Tx timestamp interrupt mode %u\n",
+ pf->ptp.tx_interrupt_mode);
+ return;
+ }
+}
+
+static bool ice_port_has_timestamps(struct ice_ptp_tx *tx)
+{
+ bool more_timestamps;
+
+ scoped_guard(spinlock_irqsave, &tx->lock) {
+ if (!tx->init)
+ return false;
+
+ more_timestamps = !bitmap_empty(tx->in_use, tx->len);
+ }
+
+ return more_timestamps;
+}
+
+static bool ice_any_port_has_timestamps(struct ice_pf *pf)
+{
+ struct ice_ptp_port *port;
+
+ scoped_guard(mutex, &pf->adapter->ports.lock) {
+ list_for_each_entry(port, &pf->adapter->ports.ports,
+ list_node) {
+ struct ice_ptp_tx *tx = &port->tx;
+
+ if (ice_port_has_timestamps(tx))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
+{
+ struct ice_hw *hw = &pf->hw;
+ unsigned int i;
+
+ /* Check software indicator */
+ switch (pf->ptp.tx_interrupt_mode) {
+ case ICE_PTP_TX_INTERRUPT_NONE:
+ return false;
+ case ICE_PTP_TX_INTERRUPT_SELF:
+ if (ice_port_has_timestamps(&pf->ptp.port.tx))
+ return true;
+ break;
+ case ICE_PTP_TX_INTERRUPT_ALL:
+ if (ice_any_port_has_timestamps(pf))
+ return true;
+ break;
default:
WARN_ONCE(1, "Unexpected Tx timestamp interrupt mode %u\n",
pf->ptp.tx_interrupt_mode);
- return ICE_TX_TSTAMP_WORK_DONE;
+ break;
+ }
+
+ /* Check hardware indicator */
+ for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) {
+ u64 tstamp_ready = 0;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
+ if (err || tstamp_ready)
+ return true;
}
+
+ return false;
}
/**
@@ -2738,7 +2758,9 @@ irqreturn_t ice_ptp_ts_irq(struct ice_pf *pf)
return IRQ_WAKE_THREAD;
case ICE_MAC_E830:
/* E830 can read timestamps in the top half using rd32() */
- if (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) {
+ ice_ptp_process_ts(pf);
+
+ if (ice_ptp_tx_tstamps_pending(pf)) {
/* Process outstanding Tx timestamps. If there
* is more work, re-arm the interrupt to trigger again.
*/
@@ -2818,6 +2840,20 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
}
/**
+ * ice_ptp_queue_work - Queue PTP periodic work for a PF
+ * @pf: Board private structure
+ *
+ * Helper function to queue PTP periodic work after VSI rebuild completes.
+ * This ensures that PTP work only runs when VSI structures are ready.
+ */
+void ice_ptp_queue_work(struct ice_pf *pf)
+{
+ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags) &&
+ pf->ptp.state == ICE_PTP_READY)
+ kthread_queue_delayed_work(pf->ptp.kworker, &pf->ptp.work, 0);
+}
+
+/**
* ice_ptp_prepare_rebuild_sec - Prepare second NAC for PTP reset or rebuild
* @pf: Board private structure
* @rebuild: rebuild if true, prepare if false
@@ -2835,10 +2871,15 @@ static void ice_ptp_prepare_rebuild_sec(struct ice_pf *pf, bool rebuild,
struct ice_pf *peer_pf = ptp_port_to_pf(port);
if (!ice_is_primary(&peer_pf->hw)) {
- if (rebuild)
+ if (rebuild) {
+ /* TODO: When implementing rebuild=true:
+ * 1. Ensure secondary PFs' VSIs are rebuilt
+ * 2. Call ice_ptp_queue_work(peer_pf) after VSI rebuild
+ */
ice_ptp_rebuild(peer_pf, reset_type);
- else
+ } else {
ice_ptp_prepare_for_reset(peer_pf, reset_type);
+ }
}
}
}
@@ -2984,9 +3025,6 @@ void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ptp->state = ICE_PTP_READY;
- /* Start periodic work going */
- kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
-
dev_info(ice_pf_to_dev(pf), "PTP reset successful\n");
return;
@@ -3191,8 +3229,9 @@ static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf)
{
switch (pf->hw.mac_type) {
case ICE_MAC_GENERIC:
- /* E822 based PHY has the clock owner process the interrupt
- * for all ports.
+ case ICE_MAC_GENERIC_3K_E825:
+ /* E82x hardware has the clock owner process timestamps for
+ * all ports.
*/
if (ice_pf_src_tmr_owned(pf))
pf->ptp.tx_interrupt_mode = ICE_PTP_TX_INTERRUPT_ALL;